diff --git a/config/kernel/linux-rockchip-next.config b/config/kernel/linux-rockchip-next.config index fef3a192a..cad3e70a7 100644 --- a/config/kernel/linux-rockchip-next.config +++ b/config/kernel/linux-rockchip-next.config @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 4.14.14 Kernel Configuration +# Linux/arm 4.14.15 Kernel Configuration # CONFIG_ARM=y CONFIG_ARM_HAS_SG_CHAIN=y @@ -1874,6 +1874,7 @@ CONFIG_ATH10K_USB=m # CONFIG_ATH10K_TRACING is not set CONFIG_WCN36XX=m # CONFIG_WCN36XX_DEBUGFS is not set +CONFIG_RTL8188EU=m CONFIG_WLAN_VENDOR_ATMEL=y CONFIG_AT76C50X_USB=m CONFIG_WLAN_VENDOR_BROADCOM=y diff --git a/config/kernel/linux-sunxi-next.config b/config/kernel/linux-sunxi-next.config index 44b895cd1..c4b2338d1 100644 --- a/config/kernel/linux-sunxi-next.config +++ b/config/kernel/linux-sunxi-next.config @@ -2216,6 +2216,7 @@ CONFIG_ATH10K_USB=m # CONFIG_ATH10K_DEBUGFS is not set # CONFIG_ATH10K_TRACING is not set # CONFIG_WCN36XX is not set +CONFIG_RTL8188EU=m CONFIG_WLAN_VENDOR_ATMEL=y CONFIG_AT76C50X_USB=m CONFIG_WLAN_VENDOR_BROADCOM=y @@ -5032,8 +5033,7 @@ CONFIG_MCS_FIR=m # CONFIG_RTLLIB is not set CONFIG_RTL8723BS=m CONFIG_R8712U=m -CONFIG_R8188EU=m -CONFIG_88EU_AP_MODE=y +# CONFIG_R8188EU is not set # CONFIG_VT6656 is not set # diff --git a/config/kernel/linux-sunxi64-next.config b/config/kernel/linux-sunxi64-next.config index 4b2295575..5b7ce872a 100644 --- a/config/kernel/linux-sunxi64-next.config +++ b/config/kernel/linux-sunxi64-next.config @@ -2017,6 +2017,7 @@ CONFIG_ATH10K_USB=m # CONFIG_ATH10K_DEBUG is not set # CONFIG_ATH10K_DEBUGFS is not set # CONFIG_WCN36XX is not set +CONFIG_RTL8188EU=m # CONFIG_WLAN_VENDOR_ATMEL is not set CONFIG_WLAN_VENDOR_BROADCOM=y CONFIG_B43=m @@ -4582,8 +4583,7 @@ CONFIG_STAGING=y # CONFIG_RTLLIB is not set CONFIG_RTL8723BS=m CONFIG_R8712U=m -CONFIG_R8188EU=m -CONFIG_88EU_AP_MODE=y +# CONFIG_R8188EU is not set # CONFIG_VT6656 is not set # diff --git a/patch/kernel/rockchip-next/91-01-rtl8188eu-kconfig-makefile.patch b/patch/kernel/rockchip-next/91-01-rtl8188eu-kconfig-makefile.patch new file mode 100644 index 000000000..4e9018082 --- /dev/null +++ b/patch/kernel/rockchip-next/91-01-rtl8188eu-kconfig-makefile.patch @@ -0,0 +1,24 @@ +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-next/91-02-rtl8188eu.patch b/patch/kernel/rockchip-next/91-02-rtl8188eu.patch new file mode 100644 index 000000000..7ec8024fe --- /dev/null +++ b/patch/kernel/rockchip-next/91-02-rtl8188eu.patch @@ -0,0 +1,315820 @@ +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