From d5e8710cbd0c1aad7c45526b815008ba8930ac32 Mon Sep 17 00:00:00 2001 From: Igor Pecovnik Date: Thu, 12 Dec 2019 07:47:18 +0100 Subject: [PATCH] Tinkerboard S: fix booting from eMMC. Closing [AR-89] --- config/kernel/linux-rockchip-current.config | 6 +- lib/compilation-prepare.sh | 12 +- ...oard-tinkerboard-enable-emmc-support.patch | 25 + .../general-fixup-dw-hdmi.patch.disabled | 12 - ...oard-tinkerboard-enable-emmc-support.patch | 25 - ...i-2001-01-rtl8188eu-kconfig-makefile.patch | 24 - .../wifi-2002-02-rtl8188eu.patch | 315825 --------------- 7 files changed, 38 insertions(+), 315891 deletions(-) create mode 100644 patch/kernel/rockchip-current/board-tinkerboard-enable-emmc-support.patch delete mode 100644 patch/kernel/rockchip-current/general-fixup-dw-hdmi.patch.disabled delete mode 100644 patch/kernel/rockchip-current/need_to_be_checked/board-tinkerboard-enable-emmc-support.patch delete mode 100644 patch/kernel/rockchip-current/need_to_be_checked/wifi-2001-01-rtl8188eu-kconfig-makefile.patch delete mode 100644 patch/kernel/rockchip-current/need_to_be_checked/wifi-2002-02-rtl8188eu.patch diff --git a/config/kernel/linux-rockchip-current.config b/config/kernel/linux-rockchip-current.config index 483077a68e..df4df614b3 100644 --- a/config/kernel/linux-rockchip-current.config +++ b/config/kernel/linux-rockchip-current.config @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 5.3.7 Kernel Configuration +# Linux/arm 5.3.15 Kernel Configuration # # @@ -1770,6 +1770,7 @@ CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 # CONFIG_BLK_DEV_CRYPTOLOOP is not set CONFIG_BLK_DEV_DRBD=m +# CONFIG_DRBD_FAULT_INJECTION is not set # CONFIG_BLK_DEV_NBD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=1 @@ -2311,7 +2312,7 @@ CONFIG_WLAN_VENDOR_TI=y # CONFIG_WL18XX is not set # CONFIG_WLCORE is not set CONFIG_RTL8822BU=m -CONFIG_RTL8188EU=m +CONFIG_RTL8188EUS=m CONFIG_RTL8812AU=m CONFIG_WLAN_VENDOR_ZYDAS=y CONFIG_USB_ZD1201=m @@ -6693,6 +6694,7 @@ CONFIG_DQL=y CONFIG_GLOB=y # CONFIG_GLOB_SELFTEST is not set CONFIG_NLATTR=y +CONFIG_LRU_CACHE=m CONFIG_CLZ_TAB=y # CONFIG_IRQ_POLL is not set CONFIG_MPILIB=y diff --git a/lib/compilation-prepare.sh b/lib/compilation-prepare.sh index a4d4d77ef1..49e6a16f69 100644 --- a/lib/compilation-prepare.sh +++ b/lib/compilation-prepare.sh @@ -35,12 +35,18 @@ compilation_prepare() process_patch_file "${SRC}/patch/misc/general-packaging-4.14.y.patch" "applying" fi - if [[ $version == "4.4."* || $version == "4.9."* ]] && [[ "$LINUXFAMILY" == rock* || "$LINUXFAMILY" == rk3399 ]]; then + if [[ $version == "4.4."* || $version == "4.9."* ]] && [[ "$LINUXFAMILY" == rockchip64 || "$LINUXFAMILY" == rk3399 ]]; then display_alert "Adjustin" "packaging" "info" cd ${SRC}/cache/sources/${LINUXSOURCEDIR} process_patch_file "${SRC}/patch/misc/general-packaging-4.4.y-rk3399.patch" "applying" fi + if [[ $version == "4.4."* ]] && [[ "$LINUXFAMILY" == rockchip ]]; then + display_alert "Adjustin" "packaging" "info" + cd ${SRC}/cache/sources/${LINUXSOURCEDIR} + process_patch_file "${SRC}/patch/misc/general-packaging-4.4.y.patch" "applying" + fi + if [[ $version == "4.9."* ]] && [[ "$LINUXFAMILY" == meson64 ]]; then display_alert "Adjustin" "packaging" "info" cd ${SRC}/cache/sources/${LINUXSOURCEDIR} @@ -153,7 +159,7 @@ compilation_prepare() fi # Wireless drivers for Xradio XR819 chipsets - if linux-version compare $version ge 3.14 && [ "$EXTRAWIFI" == yes ]; then + if linux-version compare $version ge 4.19 && [ "$LINUXFAMILY" == sunxi ] && [ "$EXTRAWIFI" == yes ]; then display_alert "Adding" "Wireless drivers for Xradio XR819 chipsets" "info" @@ -179,7 +185,7 @@ compilation_prepare() # Wireless drivers for Realtek 8188EU 8188EUS and 8188ETV chipsets - if linux-version compare $version ge 3.14 && [ "$LINUXFAMILY" == sunxi ] && [ "$EXTRAWIFI" == yes ]; then + if linux-version compare $version ge 3.14 && [ "$EXTRAWIFI" == yes ]; then # attach to specifics tag or branch local rtl8811euver="branch:v5.3.9" diff --git a/patch/kernel/rockchip-current/board-tinkerboard-enable-emmc-support.patch b/patch/kernel/rockchip-current/board-tinkerboard-enable-emmc-support.patch new file mode 100644 index 0000000000..d9e10ccb9e --- /dev/null +++ b/patch/kernel/rockchip-current/board-tinkerboard-enable-emmc-support.patch @@ -0,0 +1,25 @@ +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; ++ 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"; ++}; ++ ++&hdmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hdmi_cec_c0>; ++}; diff --git a/patch/kernel/rockchip-current/general-fixup-dw-hdmi.patch.disabled b/patch/kernel/rockchip-current/general-fixup-dw-hdmi.patch.disabled deleted file mode 100644 index 97f4f3a199..0000000000 --- a/patch/kernel/rockchip-current/general-fixup-dw-hdmi.patch.disabled +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index f108ffa92..76555b4c8 100644 ---- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -477,7 +477,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, diff --git a/patch/kernel/rockchip-current/need_to_be_checked/board-tinkerboard-enable-emmc-support.patch b/patch/kernel/rockchip-current/need_to_be_checked/board-tinkerboard-enable-emmc-support.patch deleted file mode 100644 index 207885fa07..0000000000 --- a/patch/kernel/rockchip-current/need_to_be_checked/board-tinkerboard-enable-emmc-support.patch +++ /dev/null @@ -1,25 +0,0 @@ -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>; - }; - -+&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 */ diff --git a/patch/kernel/rockchip-current/need_to_be_checked/wifi-2001-01-rtl8188eu-kconfig-makefile.patch b/patch/kernel/rockchip-current/need_to_be_checked/wifi-2001-01-rtl8188eu-kconfig-makefile.patch deleted file mode 100644 index 4e9018082d..0000000000 --- a/patch/kernel/rockchip-current/need_to_be_checked/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/patch/kernel/rockchip-current/need_to_be_checked/wifi-2002-02-rtl8188eu.patch b/patch/kernel/rockchip-current/need_to_be_checked/wifi-2002-02-rtl8188eu.patch deleted file mode 100644 index d356c74bfe..0000000000 --- a/patch/kernel/rockchip-current/need_to_be_checked/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