[PATCH] staging: Add rtl8821ce PCIe WiFi driver

Kai-Heng Feng kai.heng.feng at canonical.com
Wed May 15 11:24:01 UTC 2019


The rtl8821ce can be found on many HP and Lenovo laptops.
Users have been using out-of-tree module for a while,

The new Realtek WiFi driver, rtw88, will support rtl8821ce in 2020 or
later.

But before that happens let's include rtl8821ce in staging at the
interim.

The original tarball can be found at [1]. The driver was trimmed from
600K LOC down to 200K LOC.

[1] https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1829220/+attachment/5263936/+files/rtl8821CE_WiFi_linux_v5.2.5.2.1_30816.20190425_COEX20170310-1212.tar.xz

Cc: Larry Finger <Larry.Finger at lwfinger.net>
Signed-off-by: Kai-Heng Feng <kai.heng.feng at canonical.com>
---
 drivers/staging/Kconfig                       |     2 +
 drivers/staging/Makefile                      |     1 +
 drivers/staging/rtl8821ce/Kconfig             |    10 +
 drivers/staging/rtl8821ce/Makefile            |   103 +
 drivers/staging/rtl8821ce/TODO                |    15 +
 .../staging/rtl8821ce/core/efuse/rtw_efuse.c  |  1461 ++
 drivers/staging/rtl8821ce/core/rtw_ap.c       |  3263 ++++
 drivers/staging/rtl8821ce/core/rtw_br_ext.c   |  1286 ++
 drivers/staging/rtl8821ce/core/rtw_btcoex.c   |   363 +
 .../rtl8821ce/core/rtw_btcoex_wifionly.c      |    43 +
 drivers/staging/rtl8821ce/core/rtw_cmd.c      |  3016 ++++
 drivers/staging/rtl8821ce/core/rtw_debug.c    |   264 +
 .../staging/rtl8821ce/core/rtw_ieee80211.c    |  2271 +++
 drivers/staging/rtl8821ce/core/rtw_io.c       |   155 +
 .../staging/rtl8821ce/core/rtw_ioctl_query.c  |    24 +
 .../staging/rtl8821ce/core/rtw_ioctl_set.c    |   602 +
 drivers/staging/rtl8821ce/core/rtw_mi.c       |   834 +
 drivers/staging/rtl8821ce/core/rtw_mlme.c     |  3606 ++++
 drivers/staging/rtl8821ce/core/rtw_mlme_ext.c | 11868 +++++++++++++
 drivers/staging/rtl8821ce/core/rtw_mp.c       |  1616 ++
 drivers/staging/rtl8821ce/core/rtw_odm.c      |   380 +
 drivers/staging/rtl8821ce/core/rtw_p2p.c      |  3661 ++++
 drivers/staging/rtl8821ce/core/rtw_pwrctrl.c  |  1034 ++
 drivers/staging/rtl8821ce/core/rtw_recv.c     |  3210 ++++
 drivers/staging/rtl8821ce/core/rtw_rf.c       |   937 +
 drivers/staging/rtl8821ce/core/rtw_security.c |  2038 +++
 drivers/staging/rtl8821ce/core/rtw_sreset.c   |   213 +
 drivers/staging/rtl8821ce/core/rtw_sta_mgt.c  |   872 +
 drivers/staging/rtl8821ce/core/rtw_vht.c      |   670 +
 .../staging/rtl8821ce/core/rtw_wlan_util.c    |  2935 ++++
 drivers/staging/rtl8821ce/core/rtw_xmit.c     |  3570 ++++
 .../rtl8821ce/hal/btc/halbtc8821c1ant.c       |  5148 ++++++
 .../rtl8821ce/hal/btc/halbtc8821c1ant.h       |   461 +
 .../rtl8821ce/hal/btc/halbtc8821c2ant.c       |  5773 +++++++
 .../rtl8821ce/hal/btc/halbtc8821c2ant.h       |   470 +
 .../rtl8821ce/hal/btc/halbtc8821cwifionly.c   |   182 +
 .../rtl8821ce/hal/btc/halbtc8821cwifionly.h   |    68 +
 .../staging/rtl8821ce/hal/btc/halbtcoutsrc.h  |   987 ++
 .../staging/rtl8821ce/hal/btc/mp_precomp.h    |    64 +
 .../staging/rtl8821ce/hal/efuse/efuse_mask.h  |    15 +
 .../efuse/rtl8821c/HalEfuseMask8821C_PCIE.c   |    99 +
 .../efuse/rtl8821c/HalEfuseMask8821C_PCIE.h   |    37 +
 drivers/staging/rtl8821ce/hal/hal_btcoex.c    |  2741 +++
 .../rtl8821ce/hal/hal_btcoex_wifionly.c       |    69 +
 drivers/staging/rtl8821ce/hal/hal_com.c       |  3490 ++++
 drivers/staging/rtl8821ce/hal/hal_com_c2h.h   |   109 +
 .../staging/rtl8821ce/hal/hal_com_phycfg.c    |  4226 +++++
 drivers/staging/rtl8821ce/hal/hal_dm.c        |   331 +
 drivers/staging/rtl8821ce/hal/hal_dm.h        |    27 +
 drivers/staging/rtl8821ce/hal/hal_halmac.c    |  1832 ++
 drivers/staging/rtl8821ce/hal/hal_halmac.h    |   104 +
 drivers/staging/rtl8821ce/hal/hal_intf.c      |  1080 ++
 drivers/staging/rtl8821ce/hal/hal_mp.c        |  1414 ++
 .../rtl8821ce/hal/halmac/halmac_2_platform.h  |    80 +
 .../halmac_8821c/halmac_8821c_cfg.h           |    75 +
 .../halmac_8821c/halmac_8821c_phy.c           |    37 +
 .../halmac_8821c/halmac_8821c_pwr_seq.c       |   240 +
 .../halmac_8821c/halmac_8821c_pwr_seq.h       |    17 +
 .../halmac_8821c/halmac_api_8821c.c           |   269 +
 .../halmac_8821c/halmac_api_8821c.h           |    29 +
 .../halmac_8821c/halmac_api_8821c_pcie.c      |   251 +
 .../halmac_8821c/halmac_api_8821c_pcie.h      |    40 +
 .../halmac_8821c/halmac_func_8821c.c          |   311 +
 .../halmac_8821c/halmac_func_8821c.h          |    19 +
 .../hal/halmac/halmac_88xx/halmac_88xx_cfg.h  |   154 +
 .../hal/halmac/halmac_88xx/halmac_api_88xx.c  |  5404 ++++++
 .../hal/halmac/halmac_88xx/halmac_api_88xx.h  |   601 +
 .../halmac/halmac_88xx/halmac_api_88xx_pcie.c |   322 +
 .../halmac/halmac_88xx/halmac_api_88xx_pcie.h |    76 +
 .../hal/halmac/halmac_88xx/halmac_func_88xx.c |  3735 ++++
 .../hal/halmac/halmac_88xx/halmac_func_88xx.h |   523 +
 .../staging/rtl8821ce/hal/halmac/halmac_api.c |   359 +
 .../staging/rtl8821ce/hal/halmac/halmac_api.h |    84 +
 .../rtl8821ce/hal/halmac/halmac_bit2.h        |   226 +
 .../rtl8821ce/hal/halmac/halmac_bit_8821c.h   |  9782 +++++++++++
 .../rtl8821ce/hal/halmac/halmac_fw_info.h     |    98 +
 .../hal/halmac/halmac_fw_offload_c2h_ap.h     |   158 +
 .../hal/halmac/halmac_fw_offload_c2h_nic.h    |   124 +
 .../hal/halmac/halmac_fw_offload_h2c_ap.h     |   421 +
 .../hal/halmac/halmac_fw_offload_h2c_nic.h    |   300 +
 .../hal/halmac/halmac_h2c_extra_info_ap.h     |    70 +
 .../hal/halmac/halmac_h2c_extra_info_nic.h    |    48 +
 .../hal/halmac/halmac_intf_phy_cmd.h          |    31 +
 .../rtl8821ce/hal/halmac/halmac_module.h      |   116 +
 .../hal/halmac/halmac_original_c2h_ap.h       |   337 +
 .../hal/halmac/halmac_original_c2h_nic.h      |   230 +
 .../hal/halmac/halmac_original_h2c_ap.h       |   879 +
 .../hal/halmac/halmac_original_h2c_nic.h      |   610 +
 .../rtl8821ce/hal/halmac/halmac_pcie_reg.h    |     5 +
 .../rtl8821ce/hal/halmac/halmac_pwr_seq_cmd.h |   107 +
 .../rtl8821ce/hal/halmac/halmac_reg2.h        |  1116 ++
 .../rtl8821ce/hal/halmac/halmac_reg_8821c.h   |   737 +
 .../rtl8821ce/hal/halmac/halmac_rx_bd_ap.h    |    22 +
 .../rtl8821ce/hal/halmac/halmac_rx_bd_chip.h  |    22 +
 .../rtl8821ce/hal/halmac/halmac_rx_bd_nic.h   |    22 +
 .../rtl8821ce/hal/halmac/halmac_rx_desc_ap.h  |    89 +
 .../hal/halmac/halmac_rx_desc_chip.h          |    79 +
 .../rtl8821ce/hal/halmac/halmac_rx_desc_nic.h |    89 +
 .../rtl8821ce/hal/halmac/halmac_tx_bd_ap.h    |    92 +
 .../rtl8821ce/hal/halmac/halmac_tx_bd_chip.h  |    75 +
 .../rtl8821ce/hal/halmac/halmac_tx_bd_nic.h   |    75 +
 .../rtl8821ce/hal/halmac/halmac_tx_desc_ap.h  |   408 +
 .../hal/halmac/halmac_tx_desc_chip.h          |   266 +
 .../rtl8821ce/hal/halmac/halmac_tx_desc_nic.h |   294 +
 .../rtl8821ce/hal/halmac/halmac_type.h        |  1905 ++
 .../staging/rtl8821ce/hal/led/hal_pci_led.c   |  1214 ++
 .../staging/rtl8821ce/hal/phydm/halphyrf_ap.h |    92 +
 .../staging/rtl8821ce/hal/phydm/halphyrf_ce.c |   705 +
 .../staging/rtl8821ce/hal/phydm/halphyrf_ce.h |   101 +
 .../staging/rtl8821ce/hal/phydm/mp_precomp.h  |    20 +
 drivers/staging/rtl8821ce/hal/phydm/phydm.c   |  2147 +++
 drivers/staging/rtl8821ce/hal/phydm/phydm.h   |  1036 ++
 .../staging/rtl8821ce/hal/phydm/phydm_acs.c   |   183 +
 .../staging/rtl8821ce/hal/phydm/phydm_acs.h   |    66 +
 .../rtl8821ce/hal/phydm/phydm_adaptivity.c    |   863 +
 .../rtl8821ce/hal/phydm/phydm_adaptivity.h    |   187 +
 .../rtl8821ce/hal/phydm/phydm_adc_sampling.c  |   591 +
 .../rtl8821ce/hal/phydm/phydm_adc_sampling.h  |   118 +
 .../rtl8821ce/hal/phydm/phydm_antdiv.c        |    55 +
 .../rtl8821ce/hal/phydm/phydm_antdiv.h        |   288 +
 .../rtl8821ce/hal/phydm/phydm_beamforming.h   |    22 +
 .../staging/rtl8821ce/hal/phydm/phydm_ccx.c   |   389 +
 .../staging/rtl8821ce/hal/phydm/phydm_ccx.h   |   100 +
 .../rtl8821ce/hal/phydm/phydm_cfotracking.c   |   317 +
 .../rtl8821ce/hal/phydm/phydm_cfotracking.h   |    70 +
 .../staging/rtl8821ce/hal/phydm/phydm_debug.c |   319 +
 .../staging/rtl8821ce/hal/phydm/phydm_debug.h |   313 +
 .../staging/rtl8821ce/hal/phydm/phydm_dfs.c   |    38 +
 .../staging/rtl8821ce/hal/phydm/phydm_dfs.h   |    97 +
 .../staging/rtl8821ce/hal/phydm/phydm_dig.c   |  1129 ++
 .../staging/rtl8821ce/hal/phydm/phydm_dig.h   |   311 +
 .../hal/phydm/phydm_dynamic_rx_path.h         |    33 +
 .../hal/phydm/phydm_dynamicbbpowersaving.c    |    39 +
 .../hal/phydm/phydm_dynamicbbpowersaving.h    |    49 +
 .../hal/phydm/phydm_edcaturbocheck.h          |    26 +
 .../rtl8821ce/hal/phydm/phydm_hwconfig.c      |  1652 ++
 .../rtl8821ce/hal/phydm/phydm_hwconfig.h      |   558 +
 .../rtl8821ce/hal/phydm/phydm_interface.c     |   509 +
 .../rtl8821ce/hal/phydm/phydm_interface.h     |   376 +
 .../staging/rtl8821ce/hal/phydm/phydm_iqk.h   |    66 +
 .../staging/rtl8821ce/hal/phydm/phydm_kfree.c |   331 +
 .../staging/rtl8821ce/hal/phydm/phydm_kfree.h |    73 +
 .../rtl8821ce/hal/phydm/phydm_noisemonitor.h  |    47 +
 .../rtl8821ce/hal/phydm/phydm_pathdiv.c       |    50 +
 .../rtl8821ce/hal/phydm/phydm_pathdiv.h       |    53 +
 .../hal/phydm/phydm_powertracking_ap.h        |   302 +
 .../hal/phydm/phydm_powertracking_ce.c        |   726 +
 .../hal/phydm/phydm_powertracking_ce.h        |   297 +
 .../rtl8821ce/hal/phydm/phydm_pre_define.h    |   587 +
 .../rtl8821ce/hal/phydm/phydm_precomp.h       |    68 +
 .../staging/rtl8821ce/hal/phydm/phydm_psd.c   |   447 +
 .../staging/rtl8821ce/hal/phydm/phydm_psd.h   |   100 +
 .../rtl8821ce/hal/phydm/phydm_rainfo.c        |  1641 ++
 .../rtl8821ce/hal/phydm/phydm_rainfo.h        |   395 +
 .../staging/rtl8821ce/hal/phydm/phydm_reg.h   |   132 +
 .../rtl8821ce/hal/phydm/phydm_regdefine11ac.h |    90 +
 .../rtl8821ce/hal/phydm/phydm_regdefine11n.h  |   209 +
 .../staging/rtl8821ce/hal/phydm/phydm_types.h |   153 +
 .../staging/rtl8821ce/hal/phydm/rtchnlplan.h  |   613 +
 .../hal/phydm/rtl8821c/halhwimg8821c_bb.c     |  3421 ++++
 .../hal/phydm/rtl8821c/halhwimg8821c_bb.h     |    81 +
 .../hal/phydm/rtl8821c/halhwimg8821c_fw.h     |    59 +
 .../hal/phydm/rtl8821c/halhwimg8821c_mac.c    |   318 +
 .../hal/phydm/rtl8821c/halhwimg8821c_mac.h    |    37 +
 .../hal/phydm/rtl8821c/halhwimg8821c_rf.c     |  1793 ++
 .../hal/phydm/rtl8821c/halhwimg8821c_rf.h     |    57 +
 .../hal/phydm/rtl8821c/halphyrf_8821c.c       |   372 +
 .../hal/phydm/rtl8821c/halphyrf_8821c.h       |    63 +
 .../hal/phydm/rtl8821c/phydm_hal_api8821c.c   |   888 +
 .../hal/phydm/rtl8821c/phydm_hal_api8821c.h   |   213 +
 .../hal/phydm/rtl8821c/phydm_iqk_8821c.c      |  1991 +++
 .../hal/phydm/rtl8821c/phydm_iqk_8821c.h      |    44 +
 .../hal/phydm/rtl8821c/phydm_regconfig8821c.c |   169 +
 .../hal/phydm/rtl8821c/phydm_regconfig8821c.h |   101 +
 .../hal/phydm/rtl8821c/version_rtl8821c.h     |    10 +
 .../rtl8821ce/hal/phydm/txbf/haltxbfjaguar.h  |    13 +
 .../rtl8821ce/hal/rtl8821c/hal8821c_fw.c      | 14412 ++++++++++++++++
 .../rtl8821ce/hal/rtl8821c/hal8821c_fw.h      |    31 +
 .../rtl8821ce/hal/rtl8821c/pci/rtl8821ce.h    |   109 +
 .../hal/rtl8821c/pci/rtl8821ce_halinit.c      |   319 +
 .../hal/rtl8821c/pci/rtl8821ce_halmac.c       |   289 +
 .../rtl8821ce/hal/rtl8821c/pci/rtl8821ce_io.c |   120 +
 .../hal/rtl8821c/pci/rtl8821ce_ops.c          |   694 +
 .../hal/rtl8821c/pci/rtl8821ce_recv.c         |   435 +
 .../hal/rtl8821c/pci/rtl8821ce_xmit.c         |   984 ++
 .../staging/rtl8821ce/hal/rtl8821c/rtl8821c.h |   115 +
 .../rtl8821ce/hal/rtl8821c/rtl8821c_cmd.c     |   816 +
 .../rtl8821ce/hal/rtl8821c/rtl8821c_dm.c      |   168 +
 .../rtl8821ce/hal/rtl8821c/rtl8821c_halinit.c |   289 +
 .../rtl8821ce/hal/rtl8821c/rtl8821c_mac.c     |   183 +
 .../rtl8821ce/hal/rtl8821c/rtl8821c_ops.c     |  2777 +++
 .../rtl8821ce/hal/rtl8821c/rtl8821c_phy.c     |   968 ++
 .../staging/rtl8821ce/include/HalPwrSeqCmd.h  |   133 +
 drivers/staging/rtl8821ce/include/HalVerDef.h |   174 +
 drivers/staging/rtl8821ce/include/autoconf.h  |    38 +
 .../staging/rtl8821ce/include/basic_types.h   |   293 +
 .../rtl8821ce/include/byteorder/big_endian.h  |    88 +
 .../rtl8821ce/include/byteorder/generic.h     |   184 +
 .../rtl8821ce/include/byteorder/swab.h        |   130 +
 .../rtl8821ce/include/byteorder/swabb.h       |   152 +
 drivers/staging/rtl8821ce/include/circ_buf.h  |    29 +
 drivers/staging/rtl8821ce/include/cmd_osdep.h |    31 +
 .../staging/rtl8821ce/include/custom_gpio.h   |    24 +
 drivers/staging/rtl8821ce/include/drv_conf.h  |   165 +
 drivers/staging/rtl8821ce/include/drv_types.h |  1005 ++
 .../rtl8821ce/include/drv_types_linux.h       |    24 +
 .../staging/rtl8821ce/include/drv_types_pci.h |   199 +
 drivers/staging/rtl8821ce/include/ethernet.h  |    41 +
 drivers/staging/rtl8821ce/include/h2clbk.h    |    30 +
 .../staging/rtl8821ce/include/hal_btcoex.h    |    94 +
 .../rtl8821ce/include/hal_btcoex_wifionly.h   |    48 +
 drivers/staging/rtl8821ce/include/hal_com.h   |   557 +
 .../staging/rtl8821ce/include/hal_com_h2c.h   |   294 +
 .../staging/rtl8821ce/include/hal_com_led.h   |   258 +
 .../rtl8821ce/include/hal_com_phycfg.h        |   324 +
 .../staging/rtl8821ce/include/hal_com_reg.h   |  1110 ++
 drivers/staging/rtl8821ce/include/hal_data.h  |   819 +
 .../staging/rtl8821ce/include/hal_ic_cfg.h    |    28 +
 drivers/staging/rtl8821ce/include/hal_intf.h  |   655 +
 drivers/staging/rtl8821ce/include/hal_pg.h    |   776 +
 drivers/staging/rtl8821ce/include/hal_phy.h   |   235 +
 .../staging/rtl8821ce/include/hal_phy_reg.h   |    31 +
 drivers/staging/rtl8821ce/include/ieee80211.h |  1618 ++
 .../staging/rtl8821ce/include/ieee80211_ext.h |   289 +
 drivers/staging/rtl8821ce/include/if_ether.h  |   109 +
 drivers/staging/rtl8821ce/include/ip.h        |   138 +
 .../rtl8821ce/include/linux/wireless.h        |    79 +
 .../staging/rtl8821ce/include/mlme_osdep.h    |    35 +
 .../staging/rtl8821ce/include/mp_custom_oid.h |   350 +
 drivers/staging/rtl8821ce/include/nic_spec.h  |    44 +
 .../staging/rtl8821ce/include/osdep_intf.h    |   101 +
 .../staging/rtl8821ce/include/osdep_service.h |   570 +
 .../rtl8821ce/include/osdep_service_linux.h   |   278 +
 drivers/staging/rtl8821ce/include/pci_hal.h   |    26 +
 drivers/staging/rtl8821ce/include/pci_ops.h   |    26 +
 .../staging/rtl8821ce/include/pci_osintf.h    |    38 +
 .../staging/rtl8821ce/include/recv_osdep.h    |    58 +
 .../staging/rtl8821ce/include/rtl8821c_dm.h   |    31 +
 .../staging/rtl8821ce/include/rtl8821c_hal.h  |    42 +
 .../staging/rtl8821ce/include/rtl8821c_spec.h |   197 +
 .../staging/rtl8821ce/include/rtl8821ce_hal.h |    29 +
 .../staging/rtl8821ce/include/rtw_android.h   |    76 +
 drivers/staging/rtl8821ce/include/rtw_ap.h    |    74 +
 .../rtl8821ce/include/rtw_beamforming.h       |    25 +
 .../staging/rtl8821ce/include/rtw_br_ext.h    |    68 +
 drivers/staging/rtl8821ce/include/rtw_bt_mp.h |   278 +
 .../staging/rtl8821ce/include/rtw_btcoex.h    |   130 +
 .../rtl8821ce/include/rtw_btcoex_wifionly.h   |    28 +
 .../staging/rtl8821ce/include/rtw_byteorder.h |    36 +
 drivers/staging/rtl8821ce/include/rtw_cmd.h   |   993 ++
 drivers/staging/rtl8821ce/include/rtw_debug.h |   337 +
 .../staging/rtl8821ce/include/rtw_eeprom.h    |   114 +
 drivers/staging/rtl8821ce/include/rtw_efuse.h |   238 +
 drivers/staging/rtl8821ce/include/rtw_event.h |   114 +
 drivers/staging/rtl8821ce/include/rtw_ht.h    |   218 +
 drivers/staging/rtl8821ce/include/rtw_io.h    |   404 +
 drivers/staging/rtl8821ce/include/rtw_ioctl.h |   175 +
 .../rtl8821ce/include/rtw_ioctl_query.h       |    24 +
 .../staging/rtl8821ce/include/rtw_ioctl_rtl.h |    77 +
 .../staging/rtl8821ce/include/rtw_ioctl_set.h |    52 +
 drivers/staging/rtl8821ce/include/rtw_iol.h   |   123 +
 drivers/staging/rtl8821ce/include/rtw_mcc.h   |    19 +
 drivers/staging/rtl8821ce/include/rtw_mem.h   |    41 +
 drivers/staging/rtl8821ce/include/rtw_mi.h    |   199 +
 drivers/staging/rtl8821ce/include/rtw_mlme.h  |   885 +
 .../staging/rtl8821ce/include/rtw_mlme_ext.h  |  1085 ++
 drivers/staging/rtl8821ce/include/rtw_mp.h    |   829 +
 .../staging/rtl8821ce/include/rtw_mp_ioctl.h  |   301 +
 .../rtl8821ce/include/rtw_mp_phy_regdef.h     |  1071 ++
 drivers/staging/rtl8821ce/include/rtw_odm.h   |    49 +
 drivers/staging/rtl8821ce/include/rtw_p2p.h   |   143 +
 .../staging/rtl8821ce/include/rtw_pwrctrl.h   |   358 +
 drivers/staging/rtl8821ce/include/rtw_qos.h   |    31 +
 drivers/staging/rtl8821ce/include/rtw_recv.h  |   634 +
 drivers/staging/rtl8821ce/include/rtw_rf.h    |   237 +
 .../staging/rtl8821ce/include/rtw_security.h  |   416 +
 .../staging/rtl8821ce/include/rtw_sreset.h    |    59 +
 drivers/staging/rtl8821ce/include/rtw_tdls.h  |    24 +
 .../staging/rtl8821ce/include/rtw_version.h   |     3 +
 drivers/staging/rtl8821ce/include/rtw_vht.h   |   142 +
 drivers/staging/rtl8821ce/include/rtw_wapi.h  |   212 +
 .../staging/rtl8821ce/include/rtw_wifi_regd.h |    26 +
 drivers/staging/rtl8821ce/include/rtw_xmit.h  |   547 +
 drivers/staging/rtl8821ce/include/sta_info.h  |   542 +
 drivers/staging/rtl8821ce/include/wifi.h      |  1193 ++
 .../staging/rtl8821ce/include/wlan_bssdef.h   |   360 +
 .../staging/rtl8821ce/include/xmit_osdep.h    |    63 +
 .../rtl8821ce/os_dep/linux/ioctl_linux.c      |  8796 ++++++++++
 .../staging/rtl8821ce/os_dep/linux/ioctl_mp.c |  2071 +++
 .../rtl8821ce/os_dep/linux/mlme_linux.c       |   211 +
 .../staging/rtl8821ce/os_dep/linux/os_intfs.c |  2389 +++
 .../staging/rtl8821ce/os_dep/linux/pci_intf.c |  1574 ++
 .../rtl8821ce/os_dep/linux/recv_linux.c       |   577 +
 .../rtl8821ce/os_dep/linux/rtw_android.c      |   549 +
 .../rtl8821ce/os_dep/linux/xmit_linux.c       |   353 +
 .../staging/rtl8821ce/os_dep/osdep_service.c  |  1325 ++
 296 files changed, 206166 insertions(+)
 create mode 100644 drivers/staging/rtl8821ce/Kconfig
 create mode 100644 drivers/staging/rtl8821ce/Makefile
 create mode 100644 drivers/staging/rtl8821ce/TODO
 create mode 100644 drivers/staging/rtl8821ce/core/efuse/rtw_efuse.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_ap.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_br_ext.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_btcoex.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_btcoex_wifionly.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_cmd.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_debug.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_ieee80211.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_io.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_ioctl_query.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_ioctl_set.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_mi.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_mlme.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_mlme_ext.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_mp.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_odm.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_p2p.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_pwrctrl.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_recv.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_rf.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_security.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_sreset.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_sta_mgt.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_vht.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_wlan_util.c
 create mode 100644 drivers/staging/rtl8821ce/core/rtw_xmit.c
 create mode 100644 drivers/staging/rtl8821ce/hal/btc/halbtc8821c1ant.c
 create mode 100644 drivers/staging/rtl8821ce/hal/btc/halbtc8821c1ant.h
 create mode 100644 drivers/staging/rtl8821ce/hal/btc/halbtc8821c2ant.c
 create mode 100644 drivers/staging/rtl8821ce/hal/btc/halbtc8821c2ant.h
 create mode 100644 drivers/staging/rtl8821ce/hal/btc/halbtc8821cwifionly.c
 create mode 100644 drivers/staging/rtl8821ce/hal/btc/halbtc8821cwifionly.h
 create mode 100644 drivers/staging/rtl8821ce/hal/btc/halbtcoutsrc.h
 create mode 100644 drivers/staging/rtl8821ce/hal/btc/mp_precomp.h
 create mode 100644 drivers/staging/rtl8821ce/hal/efuse/efuse_mask.h
 create mode 100644 drivers/staging/rtl8821ce/hal/efuse/rtl8821c/HalEfuseMask8821C_PCIE.c
 create mode 100644 drivers/staging/rtl8821ce/hal/efuse/rtl8821c/HalEfuseMask8821C_PCIE.h
 create mode 100644 drivers/staging/rtl8821ce/hal/hal_btcoex.c
 create mode 100644 drivers/staging/rtl8821ce/hal/hal_btcoex_wifionly.c
 create mode 100644 drivers/staging/rtl8821ce/hal/hal_com.c
 create mode 100644 drivers/staging/rtl8821ce/hal/hal_com_c2h.h
 create mode 100644 drivers/staging/rtl8821ce/hal/hal_com_phycfg.c
 create mode 100644 drivers/staging/rtl8821ce/hal/hal_dm.c
 create mode 100644 drivers/staging/rtl8821ce/hal/hal_dm.h
 create mode 100644 drivers/staging/rtl8821ce/hal/hal_halmac.c
 create mode 100644 drivers/staging/rtl8821ce/hal/hal_halmac.h
 create mode 100644 drivers/staging/rtl8821ce/hal/hal_intf.c
 create mode 100644 drivers/staging/rtl8821ce/hal/hal_mp.c
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_2_platform.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_8821c/halmac_8821c_cfg.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_8821c/halmac_8821c_phy.c
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_8821c/halmac_8821c_pwr_seq.c
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_8821c/halmac_8821c_pwr_seq.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_8821c/halmac_api_8821c.c
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_8821c/halmac_api_8821c.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_8821c/halmac_api_8821c_pcie.c
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_8821c/halmac_api_8821c_pcie.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_8821c/halmac_func_8821c.c
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_8821c/halmac_func_8821c.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_88xx_cfg.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_api_88xx.c
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_api_88xx.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_api_88xx_pcie.c
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_api_88xx_pcie.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_func_88xx.c
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_88xx/halmac_func_88xx.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_api.c
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_api.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_bit2.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_bit_8821c.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_fw_info.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_fw_offload_c2h_ap.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_fw_offload_c2h_nic.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_fw_offload_h2c_ap.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_fw_offload_h2c_nic.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_h2c_extra_info_ap.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_h2c_extra_info_nic.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_intf_phy_cmd.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_module.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_original_c2h_ap.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_original_c2h_nic.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_original_h2c_ap.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_original_h2c_nic.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_pcie_reg.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_pwr_seq_cmd.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_reg2.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_reg_8821c.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_rx_bd_ap.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_rx_bd_chip.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_rx_bd_nic.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_rx_desc_ap.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_rx_desc_chip.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_rx_desc_nic.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_tx_bd_ap.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_tx_bd_chip.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_tx_bd_nic.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_tx_desc_ap.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_tx_desc_chip.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_tx_desc_nic.h
 create mode 100644 drivers/staging/rtl8821ce/hal/halmac/halmac_type.h
 create mode 100644 drivers/staging/rtl8821ce/hal/led/hal_pci_led.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/halphyrf_ap.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/halphyrf_ce.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/halphyrf_ce.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/mp_precomp.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_acs.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_acs.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_adaptivity.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_adaptivity.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_adc_sampling.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_adc_sampling.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_antdiv.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_antdiv.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_beamforming.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_ccx.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_ccx.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_cfotracking.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_cfotracking.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_debug.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_debug.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_dfs.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_dfs.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_dig.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_dig.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_dynamic_rx_path.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_dynamicbbpowersaving.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_dynamicbbpowersaving.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_edcaturbocheck.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_hwconfig.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_hwconfig.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_interface.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_interface.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_iqk.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_kfree.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_kfree.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_noisemonitor.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_pathdiv.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_pathdiv.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_powertracking_ap.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_powertracking_ce.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_powertracking_ce.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_pre_define.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_precomp.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_psd.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_psd.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_rainfo.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_rainfo.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_reg.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_regdefine11ac.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_regdefine11n.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/phydm_types.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtchnlplan.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtl8821c/halhwimg8821c_bb.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtl8821c/halhwimg8821c_bb.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtl8821c/halhwimg8821c_fw.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtl8821c/halhwimg8821c_mac.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtl8821c/halhwimg8821c_mac.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtl8821c/halhwimg8821c_rf.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtl8821c/halhwimg8821c_rf.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtl8821c/halphyrf_8821c.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtl8821c/halphyrf_8821c.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtl8821c/phydm_hal_api8821c.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtl8821c/phydm_hal_api8821c.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtl8821c/phydm_iqk_8821c.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtl8821c/phydm_iqk_8821c.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtl8821c/phydm_regconfig8821c.c
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtl8821c/phydm_regconfig8821c.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/rtl8821c/version_rtl8821c.h
 create mode 100644 drivers/staging/rtl8821ce/hal/phydm/txbf/haltxbfjaguar.h
 create mode 100644 drivers/staging/rtl8821ce/hal/rtl8821c/hal8821c_fw.c
 create mode 100644 drivers/staging/rtl8821ce/hal/rtl8821c/hal8821c_fw.h
 create mode 100644 drivers/staging/rtl8821ce/hal/rtl8821c/pci/rtl8821ce.h
 create mode 100644 drivers/staging/rtl8821ce/hal/rtl8821c/pci/rtl8821ce_halinit.c
 create mode 100644 drivers/staging/rtl8821ce/hal/rtl8821c/pci/rtl8821ce_halmac.c
 create mode 100644 drivers/staging/rtl8821ce/hal/rtl8821c/pci/rtl8821ce_io.c
 create mode 100644 drivers/staging/rtl8821ce/hal/rtl8821c/pci/rtl8821ce_ops.c
 create mode 100644 drivers/staging/rtl8821ce/hal/rtl8821c/pci/rtl8821ce_recv.c
 create mode 100644 drivers/staging/rtl8821ce/hal/rtl8821c/pci/rtl8821ce_xmit.c
 create mode 100644 drivers/staging/rtl8821ce/hal/rtl8821c/rtl8821c.h
 create mode 100644 drivers/staging/rtl8821ce/hal/rtl8821c/rtl8821c_cmd.c
 create mode 100644 drivers/staging/rtl8821ce/hal/rtl8821c/rtl8821c_dm.c
 create mode 100644 drivers/staging/rtl8821ce/hal/rtl8821c/rtl8821c_halinit.c
 create mode 100644 drivers/staging/rtl8821ce/hal/rtl8821c/rtl8821c_mac.c
 create mode 100644 drivers/staging/rtl8821ce/hal/rtl8821c/rtl8821c_ops.c
 create mode 100644 drivers/staging/rtl8821ce/hal/rtl8821c/rtl8821c_phy.c
 create mode 100644 drivers/staging/rtl8821ce/include/HalPwrSeqCmd.h
 create mode 100644 drivers/staging/rtl8821ce/include/HalVerDef.h
 create mode 100644 drivers/staging/rtl8821ce/include/autoconf.h
 create mode 100644 drivers/staging/rtl8821ce/include/basic_types.h
 create mode 100644 drivers/staging/rtl8821ce/include/byteorder/big_endian.h
 create mode 100644 drivers/staging/rtl8821ce/include/byteorder/generic.h
 create mode 100644 drivers/staging/rtl8821ce/include/byteorder/swab.h
 create mode 100644 drivers/staging/rtl8821ce/include/byteorder/swabb.h
 create mode 100644 drivers/staging/rtl8821ce/include/circ_buf.h
 create mode 100644 drivers/staging/rtl8821ce/include/cmd_osdep.h
 create mode 100644 drivers/staging/rtl8821ce/include/custom_gpio.h
 create mode 100644 drivers/staging/rtl8821ce/include/drv_conf.h
 create mode 100644 drivers/staging/rtl8821ce/include/drv_types.h
 create mode 100644 drivers/staging/rtl8821ce/include/drv_types_linux.h
 create mode 100644 drivers/staging/rtl8821ce/include/drv_types_pci.h
 create mode 100644 drivers/staging/rtl8821ce/include/ethernet.h
 create mode 100644 drivers/staging/rtl8821ce/include/h2clbk.h
 create mode 100644 drivers/staging/rtl8821ce/include/hal_btcoex.h
 create mode 100644 drivers/staging/rtl8821ce/include/hal_btcoex_wifionly.h
 create mode 100644 drivers/staging/rtl8821ce/include/hal_com.h
 create mode 100644 drivers/staging/rtl8821ce/include/hal_com_h2c.h
 create mode 100644 drivers/staging/rtl8821ce/include/hal_com_led.h
 create mode 100644 drivers/staging/rtl8821ce/include/hal_com_phycfg.h
 create mode 100644 drivers/staging/rtl8821ce/include/hal_com_reg.h
 create mode 100644 drivers/staging/rtl8821ce/include/hal_data.h
 create mode 100644 drivers/staging/rtl8821ce/include/hal_ic_cfg.h
 create mode 100644 drivers/staging/rtl8821ce/include/hal_intf.h
 create mode 100644 drivers/staging/rtl8821ce/include/hal_pg.h
 create mode 100644 drivers/staging/rtl8821ce/include/hal_phy.h
 create mode 100644 drivers/staging/rtl8821ce/include/hal_phy_reg.h
 create mode 100644 drivers/staging/rtl8821ce/include/ieee80211.h
 create mode 100644 drivers/staging/rtl8821ce/include/ieee80211_ext.h
 create mode 100644 drivers/staging/rtl8821ce/include/if_ether.h
 create mode 100644 drivers/staging/rtl8821ce/include/ip.h
 create mode 100644 drivers/staging/rtl8821ce/include/linux/wireless.h
 create mode 100644 drivers/staging/rtl8821ce/include/mlme_osdep.h
 create mode 100644 drivers/staging/rtl8821ce/include/mp_custom_oid.h
 create mode 100644 drivers/staging/rtl8821ce/include/nic_spec.h
 create mode 100644 drivers/staging/rtl8821ce/include/osdep_intf.h
 create mode 100644 drivers/staging/rtl8821ce/include/osdep_service.h
 create mode 100644 drivers/staging/rtl8821ce/include/osdep_service_linux.h
 create mode 100644 drivers/staging/rtl8821ce/include/pci_hal.h
 create mode 100644 drivers/staging/rtl8821ce/include/pci_ops.h
 create mode 100644 drivers/staging/rtl8821ce/include/pci_osintf.h
 create mode 100644 drivers/staging/rtl8821ce/include/recv_osdep.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtl8821c_dm.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtl8821c_hal.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtl8821c_spec.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtl8821ce_hal.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_android.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_ap.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_beamforming.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_br_ext.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_bt_mp.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_btcoex.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_btcoex_wifionly.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_byteorder.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_cmd.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_debug.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_eeprom.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_efuse.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_event.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_ht.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_io.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_ioctl.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_ioctl_query.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_ioctl_rtl.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_ioctl_set.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_iol.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_mcc.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_mem.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_mi.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_mlme.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_mlme_ext.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_mp.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_mp_ioctl.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_mp_phy_regdef.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_odm.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_p2p.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_pwrctrl.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_qos.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_recv.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_rf.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_security.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_sreset.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_tdls.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_version.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_vht.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_wapi.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_wifi_regd.h
 create mode 100644 drivers/staging/rtl8821ce/include/rtw_xmit.h
 create mode 100644 drivers/staging/rtl8821ce/include/sta_info.h
 create mode 100644 drivers/staging/rtl8821ce/include/wifi.h
 create mode 100644 drivers/staging/rtl8821ce/include/wlan_bssdef.h
 create mode 100644 drivers/staging/rtl8821ce/include/xmit_osdep.h
 create mode 100644 drivers/staging/rtl8821ce/os_dep/linux/ioctl_linux.c
 create mode 100644 drivers/staging/rtl8821ce/os_dep/linux/ioctl_mp.c
 create mode 100644 drivers/staging/rtl8821ce/os_dep/linux/mlme_linux.c
 create mode 100644 drivers/staging/rtl8821ce/os_dep/linux/os_intfs.c
 create mode 100644 drivers/staging/rtl8821ce/os_dep/linux/pci_intf.c
 create mode 100644 drivers/staging/rtl8821ce/os_dep/linux/recv_linux.c
 create mode 100644 drivers/staging/rtl8821ce/os_dep/linux/rtw_android.c
 create mode 100644 drivers/staging/rtl8821ce/os_dep/linux/xmit_linux.c
 create mode 100644 drivers/staging/rtl8821ce/os_dep/osdep_service.c

diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index d5f771fafc21..ef4ad6cab441 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -40,6 +40,8 @@ source "drivers/staging/rtl8712/Kconfig"
 
 source "drivers/staging/rtl8188eu/Kconfig"
 
+source "drivers/staging/rtl8821ce/Kconfig"
+
 source "drivers/staging/rts5208/Kconfig"
 
 source "drivers/staging/octeon/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 0da0d3f0b5e4..732e89655739 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_RTL8192E)		+= rtl8192e/
 obj-$(CONFIG_RTL8723BS)		+= rtl8723bs/
 obj-$(CONFIG_R8712U)		+= rtl8712/
 obj-$(CONFIG_R8188EU)		+= rtl8188eu/
+obj-$(CONFIG_R8821CE)		+= rtl8821ce/
 obj-$(CONFIG_RTS5208)		+= rts5208/
 obj-$(CONFIG_NETLOGIC_XLR_NET)	+= netlogic/
 obj-$(CONFIG_OCTEON_ETHERNET)	+= octeon/
diff --git a/drivers/staging/rtl8821ce/Kconfig b/drivers/staging/rtl8821ce/Kconfig
new file mode 100644
index 000000000000..6a878cf086fe
--- /dev/null
+++ b/drivers/staging/rtl8821ce/Kconfig
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+config RTL8821CE
+	tristate "Realtek 8821CE PCIE Wireless LAN NIC driver"
+	depends on WLAN && MMC && CFG80211
+	depends on m
+	select WIRELESS_EXT
+	select WEXT_PRIV
+	---help---
+	This option enables support for RTL8821CE PCI driver. It can be found
+	on many HP and Lenovo Laptops.
diff --git a/drivers/staging/rtl8821ce/Makefile b/drivers/staging/rtl8821ce/Makefile
new file mode 100644
index 000000000000..240bd9ec2cc8
--- /dev/null
+++ b/drivers/staging/rtl8821ce/Makefile
@@ -0,0 +1,103 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_RTL8821CE) := r8821ce.o
+
+r8821ce-objs += core/rtw_cmd.o \
+		core/rtw_security.o \
+		core/rtw_debug.o \
+		core/rtw_io.o \
+		core/rtw_ioctl_set.o \
+		core/rtw_ieee80211.o \
+		core/rtw_mlme.o \
+		core/rtw_mlme_ext.o \
+		core/rtw_mi.o \
+		core/rtw_wlan_util.o \
+		core/rtw_vht.o \
+		core/rtw_pwrctrl.o \
+		core/rtw_rf.o \
+		core/rtw_recv.o \
+		core/rtw_sta_mgt.o \
+		core/rtw_ap.o \
+		core/rtw_xmit.o	\
+		core/rtw_p2p.o \
+		core/rtw_br_ext.o \
+		core/rtw_sreset.o \
+		core/rtw_btcoex_wifionly.o \
+		core/rtw_btcoex.o \
+		core/rtw_odm.o \
+		core/rtw_mp.o \
+		core/efuse/rtw_efuse.o \
+		os_dep/osdep_service.o \
+		os_dep/linux/os_intfs.o \
+		os_dep/linux/pci_intf.o \
+		os_dep/linux/ioctl_linux.o \
+		os_dep/linux/xmit_linux.o \
+		os_dep/linux/mlme_linux.o \
+		os_dep/linux/recv_linux.o \
+		os_dep/linux/rtw_android.o \
+		os_dep/linux/ioctl_mp.o \
+		hal/hal_intf.o \
+		hal/hal_com.o \
+		hal/hal_com_phycfg.o \
+		hal/hal_dm.o \
+		hal/hal_btcoex_wifionly.o \
+		hal/hal_btcoex.o \
+		hal/hal_mp.o \
+		hal/led/hal_pci_led.o \
+		hal/halmac/halmac_api.o \
+		hal/halmac/halmac_88xx/halmac_api_88xx.o \
+		hal/halmac/halmac_88xx/halmac_func_88xx.o \
+		hal/halmac/halmac_88xx/halmac_api_88xx_pcie.o \
+		hal/halmac/halmac_88xx/halmac_8821c/halmac_8821c_pwr_seq.o \
+		hal/halmac/halmac_88xx/halmac_8821c/halmac_api_8821c.o \
+		hal/halmac/halmac_88xx/halmac_8821c/halmac_func_8821c.o \
+		hal/halmac/halmac_88xx/halmac_8821c/halmac_api_8821c_pcie.o \
+		hal/halmac/halmac_88xx/halmac_8821c/halmac_8821c_phy.o \
+		hal/hal_halmac.o \
+		hal/rtl8821c/rtl8821c_halinit.o \
+		hal/rtl8821c/rtl8821c_mac.o \
+		hal/rtl8821c/rtl8821c_cmd.o \
+		hal/rtl8821c/rtl8821c_phy.o \
+		hal/rtl8821c/rtl8821c_dm.o \
+		hal/rtl8821c/rtl8821c_ops.o \
+		hal/rtl8821c/hal8821c_fw.o \
+		hal/rtl8821c/pci/rtl8821ce_halinit.o \
+		hal/rtl8821c/pci/rtl8821ce_halmac.o \
+		hal/rtl8821c/pci/rtl8821ce_io.o \
+		hal/rtl8821c/pci/rtl8821ce_xmit.o \
+		hal/rtl8821c/pci/rtl8821ce_recv.o \
+		hal/rtl8821c/pci/rtl8821ce_ops.o \
+		hal/efuse/rtl8821c/HalEfuseMask8821C_PCIE.o \
+		hal/phydm/phydm_debug.o \
+		hal/phydm/phydm_antdiv.o \
+		hal/phydm/phydm_interface.o \
+		hal/phydm/phydm_hwconfig.o \
+		hal/phydm/phydm.o \
+		hal/phydm/halphyrf_ce.o \
+		hal/phydm/phydm_dig.o \
+		hal/phydm/phydm_pathdiv.o \
+		hal/phydm/phydm_rainfo.o \
+		hal/phydm/phydm_dynamicbbpowersaving.o \
+		hal/phydm/phydm_powertracking_ce.o \
+		hal/phydm/phydm_adaptivity.o \
+		hal/phydm/phydm_cfotracking.o \
+		hal/phydm/phydm_acs.o \
+		hal/phydm/phydm_dfs.o \
+		hal/phydm/phydm_adc_sampling.o \
+		hal/phydm/phydm_kfree.o \
+		hal/phydm/phydm_ccx.o \
+		hal/phydm/phydm_psd.o \
+		hal/btc/halbtc8821cwifionly.o \
+		hal/btc/halbtc8821c1ant.o \
+		hal/btc/halbtc8821c2ant.o \
+		hal/phydm/rtl8821c/halhwimg8821c_bb.o \
+		hal/phydm/rtl8821c/halhwimg8821c_mac.o \
+		hal/phydm/rtl8821c/halhwimg8821c_rf.o \
+		hal/phydm/rtl8821c/phydm_hal_api8821c.o \
+		hal/phydm/rtl8821c/phydm_regconfig8821c.o \
+		hal/phydm/rtl8821c/halphyrf_8821c.o \
+		hal/phydm/rtl8821c/phydm_iqk_8821c.o
+
+ccflags-y += -I$(srctree)/$(src)/include \
+	     -I$(srctree)/$(src)/hal/btc \
+	     -I$(srctree)/$(src)/hal/phydm \
+	     -I$(srctree)/$(src)/platform
diff --git a/drivers/staging/rtl8821ce/TODO b/drivers/staging/rtl8821ce/TODO
new file mode 100644
index 000000000000..be30f79551e1
--- /dev/null
+++ b/drivers/staging/rtl8821ce/TODO
@@ -0,0 +1,15 @@
+TODO:
+- remove unused functions, macros and variables.
+- find and remove any code for other chips that is left over
+- find and remove any code for non-PCIe that is left over
+- convert any remaining unusual variable types
+- find codes that can use %pM and %Nph formatting
+- checkpatch.pl fixes - most of the remaining ones are lines too long. Many
+  of them will require refactoring
+- merge Realtek's bugfixes and new features into the driver
+- switch to use LIB80211
+- switch to use MAC80211
+
+Please send any patches to Greg Kroah-Hartman <gregkh at linuxfoundation.org>,
+Kai-Heng Feng <kai.heng.feng at canonical.com>
+and Larry Finger <Larry.Finger at lwfinger.net>.
diff --git a/drivers/staging/rtl8821ce/core/efuse/rtw_efuse.c b/drivers/staging/rtl8821ce/core/efuse/rtw_efuse.c
new file mode 100644
index 000000000000..69188988251b
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/efuse/rtw_efuse.c
@@ -0,0 +1,1461 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * 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 <drv_types.h>
+#include <hal_data.h>
+
+#include "../hal/efuse/efuse_mask.h"
+
+/*------------------------Define local variable------------------------------*/
+u8	fakeEfuseBank = {0};
+u32	fakeEfuseUsedBytes = {0};
+u8	fakeEfuseContent[EFUSE_MAX_HW_SIZE] = {0};
+u8	fakeEfuseInitMap[EFUSE_MAX_MAP_LEN] = {0};
+u8	fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN] = {0};
+
+u32	BTEfuseUsedBytes = {0};
+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 = {0};
+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};
+
+u8	maskfileBuffer[64];
+/*------------------------Define local variable------------------------------*/
+BOOLEAN rtw_file_efuse_IsMasked(PADAPTER pAdapter, u16 Offset)
+{
+	int r = Offset / 16;
+	int c = (Offset % 16) / 2;
+	int result = 0;
+
+	if (pAdapter->registrypriv.boffefusemask)
+		return FALSE;
+
+	if (c < 4) /* Upper double word */
+		result = (maskfileBuffer[r] & (0x10 << c));
+	else
+		result = (maskfileBuffer[r] & (0x01 << (c - 4)));
+
+	return (result > 0) ? 0 : 1;
+}
+
+BOOLEAN efuse_IsMasked(PADAPTER pAdapter, u16 Offset)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+
+	if (pAdapter->registrypriv.boffefusemask)
+		return FALSE;
+
+	if (IS_HARDWARE_TYPE_8821CE(pAdapter))
+		return (IS_MASKED(8821C, _MPCIE, Offset)) ? TRUE : FALSE;
+
+	return FALSE;
+}
+
+void rtw_efuse_mask_array(PADAPTER pAdapter, u8 *pArray)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+
+#if DEV_BUS_TYPE == RT_USB_INTERFACE
+	if (IS_HARDWARE_TYPE_8821CU(pAdapter))
+		GET_MASK_ARRAY(8821C, _MUSB, pArray);
+
+#elif DEV_BUS_TYPE == RT_PCI_INTERFACE
+	if (IS_HARDWARE_TYPE_8821CE(pAdapter))
+		GET_MASK_ARRAY(8821C, _MPCIE, pArray);
+
+#elif DEV_BUS_TYPE == RT_SDIO_INTERFACE
+	if (IS_HARDWARE_TYPE_8821CS(pAdapter))
+		GET_MASK_ARRAY(8821C , _MSDIO, pArray);
+#endif /*#elif DEV_BUS_TYPE == RT_SDIO_INTERFACE*/
+}
+
+u16 rtw_get_efuse_mask_arraylen(PADAPTER pAdapter)
+{
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(pAdapter);
+
+#if DEV_BUS_TYPE == RT_USB_INTERFACE
+	if (IS_HARDWARE_TYPE_8821CU(pAdapter))
+		return GET_MASK_ARRAY_LEN(8821C, _MUSB);
+
+#elif DEV_BUS_TYPE == RT_PCI_INTERFACE
+	if (IS_HARDWARE_TYPE_8821CE(pAdapter))
+		return GET_MASK_ARRAY_LEN(8821C, _MPCIE);
+
+#elif DEV_BUS_TYPE == RT_SDIO_INTERFACE
+	if (IS_HARDWARE_TYPE_8821CS(pAdapter))
+		return GET_MASK_ARRAY_LEN(8821C, _MSDIO);
+#endif
+	return 0;
+}
+
+u8 rtw_efuse_mask_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data)
+{
+	u8	ret = _SUCCESS;
+	u16	mapLen = 0, i = 0;
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE);
+
+	ret = rtw_efuse_map_read(padapter, addr, cnts , data);
+
+	if (padapter->registrypriv.boffefusemask == 0) {
+
+		for (i = 0; i < cnts; i++) {
+			if (padapter->registrypriv.bFileMaskEfuse == _TRUE) {
+				if (rtw_file_efuse_IsMasked(padapter, addr + i)) /*use file efuse mask.*/
+					data[i] = 0xff;
+			} else {
+				/*RTW_INFO(" %s , data[%d] = %x\n", __func__, i, data[i]);*/
+				if (efuse_IsMasked(padapter, addr + i)) {
+					data[i] = 0xff;
+					/*RTW_INFO(" %s ,mask data[%d] = %x\n", __func__, i, data[i]);*/
+				}
+			}
+		}
+
+	}
+	return ret;
+
+}
+
+#include "../../hal/hal_halmac.h"
+
+void BTEfuse_PowerSwitch(PADAPTER adapter, u8 write, u8 pwrstate)
+{
+}
+
+u16 efuse_GetavailableSize(PADAPTER adapter)
+{
+	struct dvobj_priv *d;
+	u32 size = 0;
+	int err;
+
+	d = adapter_to_dvobj(adapter);
+	err = rtw_halmac_get_available_efuse_size(d, &size);
+	if (err)
+		return 0;
+
+	return size;
+}
+
+u8 efuse_bt_GetCurrentSize(PADAPTER adapter, u16 *usesize)
+{
+	u8 *efuse_map;
+
+	*usesize = 0;
+	efuse_map = rtw_malloc(EFUSE_BT_MAP_LEN);
+	if (efuse_map == NULL) {
+		RTW_DBG("%s: malloc FAIL\n", __FUNCTION__);
+		return _FAIL;
+	}
+
+	/* for get bt phy efuse last use byte */
+	hal_ReadEFuse_BT_logic_map(adapter, 0x00, EFUSE_BT_MAP_LEN, efuse_map);
+	*usesize = fakeBTEfuseUsedBytes;
+
+	if (efuse_map)
+		rtw_mfree(efuse_map, EFUSE_BT_MAP_LEN);
+
+	return _SUCCESS;
+}
+
+u16 efuse_bt_GetMaxSize(PADAPTER adapter)
+{
+	return EFUSE_BT_REAL_CONTENT_LEN;
+}
+
+void EFUSE_GetEfuseDefinition(PADAPTER adapter, u8 efusetype, u8 type, void *out, BOOLEAN test)
+{
+	struct dvobj_priv *d;
+	u32 v32 = 0;
+
+	d = adapter_to_dvobj(adapter);
+
+	if (adapter->hal_func.EFUSEGetEfuseDefinition) {
+		adapter->hal_func.EFUSEGetEfuseDefinition(adapter, efusetype, type, out, test);
+		return;
+	}
+
+	if (EFUSE_WIFI == efusetype) {
+		switch (type) {
+		case TYPE_EFUSE_MAP_LEN:
+			rtw_halmac_get_logical_efuse_size(d, &v32);
+			*(u16 *)out = (u16)v32;
+			return;
+
+		case TYPE_EFUSE_REAL_CONTENT_LEN:	
+			rtw_halmac_get_physical_efuse_size(d, &v32);
+			*(u16 *)out = (u16)v32;
+			return;
+		}
+	} else if (EFUSE_BT == efusetype) {
+		switch (type) {
+		case TYPE_EFUSE_MAP_LEN:
+			*(u16 *)out = EFUSE_BT_MAP_LEN;
+			return;
+
+		case TYPE_EFUSE_REAL_CONTENT_LEN:
+			*(u16 *)out = EFUSE_BT_REAL_CONTENT_LEN;
+			return;
+		}
+	}
+}
+
+/*
+ * read/write raw efuse data
+ */
+u8 rtw_efuse_access(PADAPTER adapter, u8 write, u16 addr, u16 cnts, u8 *data)
+{
+	struct dvobj_priv *d;
+	u8 *efuse = NULL;
+	u32 size, i;
+	int err;
+
+	d = adapter_to_dvobj(adapter);
+	err = rtw_halmac_get_physical_efuse_size(d, &size);
+	if (err)
+		size = EFUSE_MAX_SIZE;
+
+	if ((addr + cnts) > size)
+		return _FAIL;
+
+	if (_TRUE == write) {
+		err = rtw_halmac_write_physical_efuse(d, addr, cnts, data);
+		if (err)
+			return _FAIL;
+	} else {
+		if (cnts > 16)
+			efuse = rtw_zmalloc(size);
+
+		if (efuse) {
+			err = rtw_halmac_read_physical_efuse_map(d, efuse, size);
+			if (err) {
+				rtw_mfree(efuse, size);
+				return _FAIL;
+			}
+
+			_rtw_memcpy(data, efuse + addr, cnts);
+			rtw_mfree(efuse, size);
+		} else {
+			err = rtw_halmac_read_physical_efuse(d, addr, cnts, data);
+			if (err)
+				return _FAIL;
+		}
+	}
+
+	return _SUCCESS;
+}
+
+static inline void dump_buf(u8 *buf, u32 len)
+{
+	u32 i;
+
+	RTW_INFO("-----------------Len %d----------------\n", len);
+	for (i = 0; i < len; i++)
+		printk("%2.2x-", *(buf + i));
+	printk("\n");
+}
+
+/*
+ * read/write raw efuse data
+ */
+u8 rtw_efuse_bt_access(PADAPTER adapter, u8 write, u16 addr, u16 cnts, u8 *data)
+{
+	struct dvobj_priv *d;
+	u8 *efuse = NULL;
+	u32 size, i;
+	int err = _FAIL;
+
+	d = adapter_to_dvobj(adapter);
+
+	size = EFUSE_BT_REAL_CONTENT_LEN;
+
+	if ((addr + cnts) > size)
+		return _FAIL;
+
+	if (_TRUE == write) {
+		err = rtw_halmac_write_bt_physical_efuse(d, addr, cnts, data);
+		if (err == -1) {
+			RTW_ERR("%s: rtw_halmac_write_bt_physical_efuse fail!\n", __FUNCTION__);
+			return _FAIL;
+		}
+		RTW_INFO("%s: rtw_halmac_write_bt_physical_efuse OK! data 0x%x\n", __FUNCTION__, *data);
+	} else {
+		efuse = rtw_zmalloc(size);
+
+		if (efuse) {
+			err = rtw_halmac_read_bt_physical_efuse_map(d, efuse, size);
+			
+			if (err == -1) {
+				RTW_ERR("%s: rtw_halmac_read_bt_physical_efuse_map fail!\n", __FUNCTION__);
+				rtw_mfree(efuse, size);
+				return _FAIL;
+			}
+			dump_buf(efuse + addr, cnts);
+
+			_rtw_memcpy(data, efuse + addr, cnts);
+
+			RTW_INFO("%s: rtw_halmac_read_bt_physical_efuse_map ok! data 0x%x\n", __FUNCTION__, *data);
+			rtw_mfree(efuse, size);
+		}
+	}
+
+	return _SUCCESS;
+}
+
+u8 rtw_efuse_map_read(PADAPTER adapter, u16 addr, u16 cnts, u8 *data)
+{
+	struct dvobj_priv *d;
+	u8 *efuse = NULL;
+	u32 size, i;
+	int err;
+
+	d = adapter_to_dvobj(adapter);
+	err = rtw_halmac_get_logical_efuse_size(d, &size);
+	if (err)
+		return _FAIL;
+
+	/* size error handle */
+	if ((addr + cnts) > size) {
+		if (addr < size)
+			cnts = size - addr;
+		else
+			return _FAIL;
+	}
+
+	if (cnts > 16)
+		efuse = rtw_zmalloc(size);
+
+	if (efuse) {
+		err = rtw_halmac_read_logical_efuse_map(d, efuse, size);
+		if (err) {
+			rtw_mfree(efuse, size);
+			return _FAIL;
+		}
+
+		_rtw_memcpy(data, efuse + addr, cnts);
+		rtw_mfree(efuse, size);
+	} else {
+		err = rtw_halmac_read_logical_efuse(d, addr, cnts, data);
+		if (err)
+			return _FAIL;
+	}
+
+	return _SUCCESS;
+}
+
+u8 rtw_efuse_map_write(PADAPTER adapter, u16 addr, u16 cnts, u8 *data)
+{
+	struct dvobj_priv *d;
+	u8 *efuse = NULL;
+	u32 size, i;
+	int err;
+	u8 mask_buf[64] = "";
+	u16 mask_len = sizeof(u8) * rtw_get_efuse_mask_arraylen(adapter);
+
+	d = adapter_to_dvobj(adapter);
+	err = rtw_halmac_get_logical_efuse_size(d, &size);
+	if (err)
+		return _FAIL;
+
+	if ((addr + cnts) > size)
+		return _FAIL;
+
+	efuse = rtw_zmalloc(size);
+	if (!efuse)
+		return _FAIL;
+
+	err = rtw_halmac_read_logical_efuse_map(d, efuse, size);
+	if (err) {
+		rtw_mfree(efuse, size);
+		return _FAIL;
+	}
+
+	_rtw_memcpy(efuse + addr, data, cnts);
+
+	if (adapter->registrypriv.boffefusemask == 0) {
+		RTW_INFO("Use mask Array Len: %d\n", mask_len);
+
+		if (mask_len != 0) {
+			if (adapter->registrypriv.bFileMaskEfuse == _TRUE)
+				_rtw_memcpy(mask_buf, maskfileBuffer, mask_len);
+			else
+				rtw_efuse_mask_array(adapter, mask_buf);
+
+			err = rtw_halmac_write_logical_efuse_map(d, efuse, size, mask_buf, mask_len);
+		} else
+			err = rtw_halmac_write_logical_efuse_map(d, efuse, size, NULL, 0);
+	} else {
+		_rtw_memset(mask_buf, 0xFF, sizeof(mask_buf));
+		RTW_INFO("Efuse mask off\n");
+		err = rtw_halmac_write_logical_efuse_map(d, efuse, size, mask_buf, size/16);
+	}
+
+	if (err) {
+		rtw_mfree(efuse, size);
+		return _FAIL;
+	}
+
+	rtw_mfree(efuse, size);
+
+	return _SUCCESS;
+}
+
+u8 rtw_BT_efuse_map_read(PADAPTER adapter, u16 addr, u16 cnts, u8 *data)
+{
+	hal_ReadEFuse_BT_logic_map(adapter,addr, cnts, data);
+
+	return _SUCCESS;
+}
+
+u8 rtw_BT_efuse_map_write(PADAPTER adapter, u16 addr, u16 cnts, u8 *data)
+{
+#define RT_ASSERT_RET(expr)									\
+	if (!(expr)) {										\
+		printk("Assertion failed! %s at ......\n", #expr);				\
+		printk("	  ......%s,%s, line=%d\n",__FILE__, __FUNCTION__, __LINE__);	\
+		return _FAIL;	\
+	}
+
+	u8	offset, word_en;
+	u8	*map;
+	u8	newdata[PGPKT_DATA_SIZE];
+	s32 i = 0, j = 0, idx;
+	u8	ret = _SUCCESS;
+	u16 mapLen = 1024;
+
+	if ((addr + cnts) > mapLen)
+		return _FAIL;
+
+	RT_ASSERT_RET(PGPKT_DATA_SIZE == 8); /* have to be 8 byte alignment */
+	RT_ASSERT_RET((mapLen & 0x7) == 0); /* have to be PGPKT_DATA_SIZE alignment for memcpy */
+
+	map = rtw_zmalloc(mapLen);
+	if (map == NULL)
+		return _FAIL;
+
+	ret = rtw_BT_efuse_map_read(adapter, 0, mapLen, map);
+	if (ret == _FAIL)
+		goto exit;
+	RTW_INFO("OFFSET\tVALUE(hex)\n");
+	for (i = 0; i < mapLen; i += 16) { /* set 512 because the iwpriv's extra size have limit 0x7FF */
+		RTW_INFO("0x%03x\t", i);
+		for (j = 0; j < 8; j++)
+			RTW_INFO("%02X ", map[i + j]);
+		RTW_INFO("\t");
+		for (; j < 16; j++)
+			RTW_INFO("%02X ", map[i + j]);
+		RTW_INFO("\n");
+	}
+	RTW_INFO("\n");
+
+	idx = 0;
+	offset = (addr >> 3);
+	while (idx < cnts) {
+		word_en = 0xF;
+		j = (addr + idx) & 0x7;
+		_rtw_memcpy(newdata, &map[offset << 3], PGPKT_DATA_SIZE);
+		for (i = j; i < PGPKT_DATA_SIZE && idx < cnts; i++, idx++) {
+			if (data[idx] != map[addr + idx]) {
+				word_en &= ~BIT(i >> 1);
+				newdata[i] = data[idx];
+			}
+		}
+
+		if (word_en != 0xF) {
+			ret = EfusePgPacketWrite_BT(adapter, offset, word_en, newdata, _FALSE);
+			RTW_INFO("offset=%x\n", offset);
+			RTW_INFO("word_en=%x\n", word_en);
+			RTW_INFO("%s: data=", __FUNCTION__);
+			for (i = 0; i < PGPKT_DATA_SIZE; i++)
+				RTW_INFO("0x%02X ", newdata[i]);
+			RTW_INFO("\n");
+			if (ret == _FAIL)
+				break;
+		}
+		offset++;
+	}
+exit:
+	rtw_mfree(map, mapLen);
+	return _SUCCESS;
+}
+
+VOID hal_ReadEFuse_BT_logic_map(
+	PADAPTER	padapter,
+	u16			_offset,
+	u16			_size_byte,
+	u8			*pbuf
+)
+{
+
+	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(padapter);
+	PEFUSE_HAL		pEfuseHal = &pHalData->EfuseHal;
+
+	u8	*efuseTbl, *phyefuse;
+	u8	bank;
+	u16	eFuse_Addr = 0;
+	u8	efuseHeader, efuseExtHdr, efuseData;
+	u8	offset, wden;
+	u16	i, total, used;
+	u8	efuse_usage;
+
+	/* */
+	/* Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */
+	/* */
+	if ((_offset + _size_byte) > EFUSE_BT_MAP_LEN) {
+		RTW_INFO("%s: Invalid offset(%#x) with read bytes(%#x)!!\n", __FUNCTION__, _offset, _size_byte);
+		return;
+	}
+
+	efuseTbl = rtw_malloc(EFUSE_BT_MAP_LEN);
+	phyefuse = rtw_malloc(EFUSE_BT_REAL_CONTENT_LEN);
+	if (efuseTbl == NULL || phyefuse == NULL) {
+		RTW_INFO("%s: efuseTbl or phyefuse malloc fail!\n", __FUNCTION__);
+		goto exit;
+	}
+
+	/* 0xff will be efuse default value instead of 0x00. */
+	_rtw_memset(efuseTbl, 0xFF, EFUSE_BT_MAP_LEN);
+	_rtw_memset(phyefuse, 0xFF, EFUSE_BT_REAL_CONTENT_LEN);
+
+	if (rtw_efuse_bt_access(padapter, _FALSE, 0, EFUSE_BT_REAL_CONTENT_LEN, phyefuse))
+		dump_buf(phyefuse, EFUSE_BT_REAL_BANK_CONTENT_LEN);
+	
+	total = BANK_NUM;
+	for (bank = 1; bank <= total; bank++) { /* 8723d Max bake 0~2 */
+		eFuse_Addr = 0;
+
+		while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) {
+			/* ReadEFuseByte(padapter, eFuse_Addr++, &efuseHeader, bPseudoTest); */
+			efuseHeader = phyefuse[eFuse_Addr++];
+
+			if (efuseHeader == 0xFF)
+				break;
+			RTW_INFO("%s: efuse[%#X]=0x%02x (header)\n", __FUNCTION__, (((bank - 1) * EFUSE_BT_REAL_CONTENT_LEN) + eFuse_Addr - 1), efuseHeader);
+
+			/* Check PG header for section num. */
+			if (EXT_HEADER(efuseHeader)) {	/* extended header */
+				offset = GET_HDR_OFFSET_2_0(efuseHeader);
+				RTW_INFO("%s: extended header offset_2_0=0x%X\n", __FUNCTION__, offset);
+
+				/* ReadEFuseByte(padapter, eFuse_Addr++, &efuseExtHdr, bPseudoTest); */
+				efuseExtHdr = phyefuse[eFuse_Addr++];
+
+				RTW_INFO("%s: efuse[%#X]=0x%02x (ext header)\n", __FUNCTION__, (((bank - 1) * EFUSE_BT_REAL_CONTENT_LEN) + eFuse_Addr - 1), efuseExtHdr);
+				if (ALL_WORDS_DISABLED(efuseExtHdr))
+					continue;
+
+				offset |= ((efuseExtHdr & 0xF0) >> 1);
+				wden = (efuseExtHdr & 0x0F);
+			} else {
+				offset = ((efuseHeader >> 4) & 0x0f);
+				wden = (efuseHeader & 0x0f);
+			}
+
+			if (offset < EFUSE_BT_MAX_SECTION) {
+				u16 addr;
+
+				/* Get word enable value from PG header */
+				RTW_INFO("%s: Offset=%d Worden=%#X\n", __FUNCTION__, offset, wden);
+
+				addr = offset * PGPKT_DATA_SIZE;
+				for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+					/* Check word enable condition in the section */
+					if (!(wden & (0x01 << i))) {
+						efuseData = 0;
+						/* ReadEFuseByte(padapter, eFuse_Addr++, &efuseData, bPseudoTest); */
+						efuseData = phyefuse[eFuse_Addr++];
+
+						RTW_INFO("%s: efuse[%#X]=0x%02X\n", __FUNCTION__, eFuse_Addr - 1, efuseData);
+						efuseTbl[addr] = efuseData;
+
+						efuseData = 0;
+						/* ReadEFuseByte(padapter, eFuse_Addr++, &efuseData, bPseudoTest); */
+						efuseData = phyefuse[eFuse_Addr++];
+
+						RTW_INFO("%s: efuse[%#X]=0x%02X\n", __FUNCTION__, eFuse_Addr - 1, efuseData);
+						efuseTbl[addr + 1] = efuseData;
+					}
+					addr += 2;
+				}
+			} else {
+				RTW_INFO("%s: offset(%d) is illegal!!\n", __FUNCTION__, offset);
+				eFuse_Addr += Efuse_CalculateWordCnts(wden) * 2;
+			}
+		}
+
+		if ((eFuse_Addr - 1) < total) {
+			RTW_INFO("%s: bank(%d) data end at %#x\n", __FUNCTION__, bank, eFuse_Addr - 1);
+			break;
+		}
+	}
+
+	/* switch bank back to bank 0 for later BT and wifi use. */
+	//hal_EfuseSwitchToBank(padapter, 0, bPseudoTest);
+
+	/* Copy from Efuse map to output pointer memory!!! */
+	for (i = 0; i < _size_byte; i++)
+		pbuf[i] = efuseTbl[_offset + i];
+	/* Calculate Efuse utilization */
+	total = EFUSE_BT_REAL_BANK_CONTENT_LEN;
+
+	used = eFuse_Addr - 1;
+
+	if (total)
+		efuse_usage = (u8)((used * 100) / total);
+	else
+		efuse_usage = 100;
+
+	fakeBTEfuseUsedBytes = used;
+	RTW_INFO("%s: BTEfuseUsed last Bytes = %#x\n", __FUNCTION__, fakeBTEfuseUsedBytes);
+
+exit:
+	if (efuseTbl)
+		rtw_mfree(efuseTbl, EFUSE_BT_MAP_LEN);
+	if (phyefuse)
+		rtw_mfree(phyefuse, EFUSE_BT_REAL_BANK_CONTENT_LEN);
+}
+
+static u8 hal_EfusePartialWriteCheck(
+	PADAPTER		padapter,
+	u8				efuseType,
+	u16				*pAddr,
+	PPGPKT_STRUCT	pTargetPkt,
+	u8				bPseudoTest)
+{
+	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(padapter);
+	PEFUSE_HAL		pEfuseHal = &pHalData->EfuseHal;
+	u8	bRet = _FALSE;
+	u16	startAddr = 0, efuse_max_available_len = EFUSE_BT_REAL_BANK_CONTENT_LEN, efuse_max = EFUSE_BT_REAL_BANK_CONTENT_LEN;
+	u8	efuse_data = 0;
+
+	startAddr = (u16)fakeBTEfuseUsedBytes;
+
+	startAddr %= efuse_max;
+	RTW_INFO("%s: startAddr=%#X\n", __FUNCTION__, startAddr);
+
+	while (1) {
+		if (startAddr >= efuse_max_available_len) {
+			bRet = _FALSE;
+			RTW_INFO("%s: startAddr(%d) >= efuse_max_available_len(%d)\n",
+				__FUNCTION__, startAddr, efuse_max_available_len);
+			break;
+		}
+		if (rtw_efuse_bt_access(padapter, _FALSE, startAddr, 1, &efuse_data)&& (efuse_data != 0xFF)) {
+			bRet = _FALSE;
+			RTW_INFO("%s: Something Wrong! last bytes(%#X=0x%02X) is not 0xFF\n",
+				 __FUNCTION__, startAddr, efuse_data);
+			break;
+		} else {
+			/* not used header, 0xff */
+			*pAddr = startAddr;
+			/*			RTW_INFO("%s: Started from unused header offset=%d\n", __FUNCTION__, startAddr)); */
+			bRet = _TRUE;
+			break;
+		}
+	}
+
+	return bRet;
+}
+
+static u8 hal_EfusePgPacketWrite2ByteHeader(
+	PADAPTER		padapter,
+	u8				efuseType,
+	u16				*pAddr,
+	PPGPKT_STRUCT	pTargetPkt,
+	u8				bPseudoTest)
+{
+	u16	efuse_addr, efuse_max_available_len = EFUSE_BT_REAL_BANK_CONTENT_LEN;
+	u8	pg_header = 0, tmp_header = 0;
+	u8	repeatcnt = 0;
+
+	/*	RTW_INFO("%s\n", __FUNCTION__); */
+
+	efuse_addr = *pAddr;
+	if (efuse_addr >= efuse_max_available_len) {
+		RTW_INFO("%s: addr(%d) over avaliable(%d)!!\n", __FUNCTION__, efuse_addr, efuse_max_available_len);
+		return _FALSE;
+	}
+
+	pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F;
+	/*	RTW_INFO("%s: pg_header=0x%x\n", __FUNCTION__, pg_header); */
+
+	do {
+		
+		rtw_efuse_bt_access(padapter, _TRUE, efuse_addr, 1, &pg_header);
+		rtw_efuse_bt_access(padapter, _FALSE, efuse_addr, 1, &tmp_header);
+
+		if (tmp_header != 0xFF)
+			break;
+		if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) {
+			RTW_INFO("%s: Repeat over limit for pg_header!!\n", __FUNCTION__);
+			return _FALSE;
+		}
+	} while (1);
+
+	if (tmp_header != pg_header) {
+		RTW_ERR("%s: PG Header Fail!!(pg=0x%02X read=0x%02X)\n", __FUNCTION__, pg_header, tmp_header);
+		return _FALSE;
+	}
+
+	/* to write ext_header */
+	efuse_addr++;
+	pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en;
+
+	do {
+		rtw_efuse_bt_access(padapter, _TRUE, efuse_addr, 1, &pg_header);
+		rtw_efuse_bt_access(padapter, _FALSE, efuse_addr, 1, &tmp_header);
+
+		if (tmp_header != 0xFF)
+			break;
+		if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) {
+			RTW_INFO("%s: Repeat over limit for ext_header!!\n", __FUNCTION__);
+			return _FALSE;
+		}
+	} while (1);
+
+	if (tmp_header != pg_header) {	/* offset PG fail */
+		RTW_ERR("%s: PG EXT Header Fail!!(pg=0x%02X read=0x%02X)\n", __FUNCTION__, pg_header, tmp_header);
+		return _FALSE;
+	}
+
+	*pAddr = efuse_addr;
+
+	return _TRUE;
+}
+
+static u8 hal_EfusePgPacketWrite1ByteHeader(
+	PADAPTER		pAdapter,
+	u8				efuseType,
+	u16				*pAddr,
+	PPGPKT_STRUCT	pTargetPkt,
+	u8				bPseudoTest)
+{
+	u8	bRet = _FALSE;
+	u8	pg_header = 0, tmp_header = 0;
+	u16	efuse_addr = *pAddr;
+	u8	repeatcnt = 0;
+
+	/*	RTW_INFO("%s\n", __FUNCTION__); */
+	pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en;
+
+	do {
+		rtw_efuse_bt_access(pAdapter, _TRUE, efuse_addr, 1, &pg_header);
+		rtw_efuse_bt_access(pAdapter, _FALSE, efuse_addr, 1, &tmp_header);
+
+		if (tmp_header != 0xFF)
+			break;
+		if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) {
+			RTW_INFO("%s: Repeat over limit for pg_header!!\n", __FUNCTION__);
+			return _FALSE;
+		}
+	} while (1);
+
+	if (tmp_header != pg_header) {
+		RTW_ERR("%s: PG Header Fail!!(pg=0x%02X read=0x%02X)\n", __FUNCTION__, pg_header, tmp_header);
+		return _FALSE;
+	}
+
+	*pAddr = efuse_addr;
+
+	return _TRUE;
+}
+
+static u8 hal_EfusePgPacketWriteHeader(
+	PADAPTER		padapter,
+	u8				efuseType,
+	u16				*pAddr,
+	PPGPKT_STRUCT	pTargetPkt,
+	u8				bPseudoTest)
+{
+	u8 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 u8
+Hal_EfuseWordEnableDataWrite(
+	PADAPTER	padapter,
+	u16			efuse_addr,
+	u8			word_en,
+	u8			*data,
+	u8			bPseudoTest)
+{
+	u16	tmpaddr = 0;
+	u16	start_addr = efuse_addr;
+	u8	badworden = 0x0F;
+	u8	tmpdata[PGPKT_DATA_SIZE];
+
+	/*	RTW_INFO("%s: efuse_addr=%#x word_en=%#x\n", __FUNCTION__, efuse_addr, word_en); */
+	_rtw_memset(tmpdata, 0xFF, PGPKT_DATA_SIZE);
+
+	if (!(word_en & BIT(0))) {
+		tmpaddr = start_addr;
+		rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[0]);
+		rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[1]);
+		rtw_efuse_bt_access(padapter, _FALSE, tmpaddr, 1, &tmpdata[0]);
+		rtw_efuse_bt_access(padapter, _FALSE, tmpaddr + 1, 1, &tmpdata[1]);
+		if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1]))
+			badworden &= (~BIT(0));
+	}
+	if (!(word_en & BIT(1))) {
+		tmpaddr = start_addr;
+		rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[2]);
+		rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[3]);
+		rtw_efuse_bt_access(padapter, _FALSE, tmpaddr, 1, &tmpdata[2]);
+		rtw_efuse_bt_access(padapter, _FALSE, tmpaddr + 1, 1, &tmpdata[3]);
+		if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3]))
+			badworden &= (~BIT(1));
+	}
+	if (!(word_en & BIT(2))) {
+		tmpaddr = start_addr;
+		rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[4]);
+		rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[5]);
+		rtw_efuse_bt_access(padapter, _FALSE, tmpaddr, 1, &tmpdata[4]);
+		rtw_efuse_bt_access(padapter, _FALSE, tmpaddr + 1, 1, &tmpdata[5]);
+		if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5]))
+			badworden &= (~BIT(2));
+	}
+	if (!(word_en & BIT(3))) {
+		tmpaddr = start_addr;
+		rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[6]);
+		rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[7]);
+		rtw_efuse_bt_access(padapter, _FALSE, tmpaddr, 1, &tmpdata[6]);
+		rtw_efuse_bt_access(padapter, _FALSE, tmpaddr + 1, 1, &tmpdata[7]);
+
+		if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7]))
+			badworden &= (~BIT(3));
+	}
+
+	return badworden;
+}
+
+static void
+hal_EfuseConstructPGPkt(
+	u8				offset,
+	u8				word_en,
+	u8				*pData,
+	PPGPKT_STRUCT	pTargetPkt)
+{
+	_rtw_memset(pTargetPkt->data, 0xFF, PGPKT_DATA_SIZE);
+	pTargetPkt->offset = offset;
+	pTargetPkt->word_en = word_en;
+	efuse_WordEnableDataRead(word_en, pData, pTargetPkt->data);
+	pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en);
+}
+
+static u8
+hal_EfusePgPacketWriteData(
+	PADAPTER		pAdapter,
+	u8				efuseType,
+	u16				*pAddr,
+	PPGPKT_STRUCT	pTargetPkt,
+	u8				bPseudoTest)
+{
+	u16	efuse_addr;
+	u8	badworden;
+
+	efuse_addr = *pAddr;
+	badworden = Hal_EfuseWordEnableDataWrite(pAdapter, efuse_addr + 1, pTargetPkt->word_en, pTargetPkt->data, bPseudoTest);
+	if (badworden != 0x0F) {
+		RTW_INFO("%s: Fail!!\n", __FUNCTION__);
+		return _FALSE;
+	} else
+		RTW_INFO("%s: OK!!\n", __FUNCTION__);
+
+	return _TRUE;
+}
+
+/* ***********************************************************
+ *				Efuse related code
+ * *********************************************************** */
+static u8
+hal_EfuseSwitchToBank(
+	PADAPTER	padapter,
+	u8			bank,
+	u8			bPseudoTest)
+{
+	u8 bRet = _FALSE;
+	u32 value32 = 0;
+
+	RTW_INFO("%s: Efuse switch bank to %d\n", __FUNCTION__, bank);
+	if (bPseudoTest) {
+		fakeEfuseBank = bank;
+		bRet = _TRUE;
+	} else {
+		value32 = rtw_read32(padapter, 0x34);
+		bRet = _TRUE;
+		switch (bank) {
+		case 0:
+			value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0);
+			break;
+		case 1:
+			value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_0);
+			break;
+		case 2:
+			value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_1);
+			break;
+		case 3:
+			value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_2);
+			break;
+		default:
+			value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0);
+			bRet = _FALSE;
+			break;
+		}
+		rtw_write32(padapter, 0x34, value32);
+	}
+
+	return bRet;
+}
+
+#define EFUSE_CTRL				0x30		/* E-Fuse Control. */
+
+/*  11/16/2008 MH Read one byte from real Efuse. */
+u8
+efuse_OneByteRead(
+	IN	PADAPTER	pAdapter,
+	IN	u16			addr,
+	IN	u8			*data,
+	IN	BOOLEAN		bPseudoTest)
+{
+	u32	tmpidx = 0;
+	u8	bResult;
+	u8	readbyte;
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(pAdapter);
+
+	if (IS_HARDWARE_TYPE_8723B(pAdapter) ||
+	    (IS_HARDWARE_TYPE_8192E(pAdapter) && (!IS_A_CUT(pHalData->version_id))) ||
+	    (IS_VENDOR_8188E_I_CUT_SERIES(pAdapter)) || (IS_CHIP_VENDOR_SMIC(pHalData->version_id))
+	   ) {
+		/* <20130121, Kordan> For SMIC EFUSE specificatoin. */
+		/* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8])	 */
+		/* phy_set_mac_reg(pAdapter, 0x34, BIT11, 0); */
+		rtw_write16(pAdapter, 0x34, rtw_read16(pAdapter, 0x34) & (~BIT11));
+	}
+
+	/* -----------------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	 */
+	/* Write bit 32 0 */
+	readbyte = rtw_read8(pAdapter, EFUSE_CTRL + 3);
+	rtw_write8(pAdapter, EFUSE_CTRL + 3, (readbyte & 0x7f));
+
+	while (!(0x80 & rtw_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 1000)) {
+		rtw_mdelay_os(1);
+		tmpidx++;
+	}
+	if (tmpidx < 100) {
+		*data = rtw_read8(pAdapter, EFUSE_CTRL);
+		bResult = _TRUE;
+	} else {
+		*data = 0xff;
+		bResult = _FALSE;
+		RTW_INFO("%s: [ERROR] addr=0x%x bResult=%d time out 1s !!!\n", __FUNCTION__, addr, bResult);
+		RTW_INFO("%s: [ERROR] EFUSE_CTRL =0x%08x !!!\n", __FUNCTION__, rtw_read32(pAdapter, EFUSE_CTRL));
+	}
+
+	return bResult;
+}
+
+static u16
+hal_EfuseGetCurrentSize_BT(
+	PADAPTER	padapter,
+	u8			bPseudoTest)
+{
+	u16 btusedbytes;
+	u16	efuse_addr;
+	u8	bank, startBank;
+	u8	hoffset = 0, hworden = 0;
+	u8	efuse_data, word_cnts = 0;
+	u16	retU2 = 0;
+	u8 bContinual = _TRUE;
+
+	btusedbytes = fakeBTEfuseUsedBytes;
+
+	efuse_addr = (u16)((btusedbytes % EFUSE_BT_REAL_BANK_CONTENT_LEN));
+	startBank = (u8)(1 + (btusedbytes / EFUSE_BT_REAL_BANK_CONTENT_LEN));
+
+	RTW_INFO("%s: start from bank=%d addr=0x%X\n", __FUNCTION__, startBank, efuse_addr);
+	retU2 = EFUSE_BT_REAL_CONTENT_LEN - EFUSE_PROTECT_BYTES_BANK;
+
+	for (bank = startBank; bank < 3; bank++) {
+		if (hal_EfuseSwitchToBank(padapter, bank, bPseudoTest) == _FALSE) {
+			RTW_ERR("%s: switch bank(%d) Fail!!\n", __FUNCTION__, bank);
+			/* bank = EFUSE_MAX_BANK; */
+			break;
+		}
+
+		/* only when bank is switched we have to reset the efuse_addr. */
+		if (bank != startBank)
+			efuse_addr = 0;
+
+		while (AVAILABLE_EFUSE_ADDR(efuse_addr)) {
+			if (rtw_efuse_bt_access(padapter, _FALSE, efuse_addr, 1, &efuse_data) == _FALSE) {
+				RTW_ERR("%s: efuse_OneByteRead Fail! addr=0x%X !!\n", __FUNCTION__, efuse_addr);
+				/* bank = EFUSE_MAX_BANK; */
+				break;
+			}
+			RTW_INFO("%s: efuse_OneByteRead ! addr=0x%X !efuse_data=0x%X! bank =%d\n", __FUNCTION__, efuse_addr, efuse_data, bank);
+
+			if (efuse_data == 0xFF)
+				break;
+
+			if (EXT_HEADER(efuse_data)) {
+				hoffset = GET_HDR_OFFSET_2_0(efuse_data);
+				efuse_addr++;
+				rtw_efuse_bt_access(padapter, _FALSE, efuse_addr, 1, &efuse_data);
+				RTW_INFO("%s: efuse_OneByteRead EXT_HEADER ! addr=0x%X !efuse_data=0x%X! bank =%d\n", __FUNCTION__, efuse_addr, efuse_data, bank);
+
+				if (ALL_WORDS_DISABLED(efuse_data)) {
+					efuse_addr++;
+					continue;
+				}
+
+				/*				hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); */
+				hoffset |= ((efuse_data & 0xF0) >> 1);
+				hworden = efuse_data & 0x0F;
+			} else {
+				hoffset = (efuse_data >> 4) & 0x0F;
+				hworden =  efuse_data & 0x0F;
+			}
+
+			RTW_INFO(FUNC_ADPT_FMT": Offset=%d Worden=%#X\n",
+				 FUNC_ADPT_ARG(padapter), hoffset, hworden);
+
+			word_cnts = Efuse_CalculateWordCnts(hworden);
+			/* read next header */
+			efuse_addr += (word_cnts * 2) + 1;
+		}
+		/* Check if we need to check next bank efuse */
+		if (efuse_addr < retU2)
+			break;/* don't need to check next bank. */
+	}
+	retU2 = ((bank - 1) * EFUSE_BT_REAL_BANK_CONTENT_LEN) + efuse_addr;
+
+	fakeBTEfuseUsedBytes = retU2;
+	RTW_INFO("%s: CurrentSize=%d\n", __FUNCTION__, retU2);
+	return retU2;
+}
+
+static u8
+hal_BT_EfusePgCheckAvailableAddr(
+	PADAPTER	pAdapter,
+	u8		bPseudoTest)
+{
+	u16	max_available = EFUSE_BT_REAL_CONTENT_LEN - EFUSE_PROTECT_BYTES_BANK;
+	u16	current_size = 0;
+
+	 RTW_INFO("%s: max_available=%d\n", __FUNCTION__, max_available);
+	current_size = hal_EfuseGetCurrentSize_BT(pAdapter, bPseudoTest);
+	if (current_size >= max_available) {
+		RTW_INFO("%s: Error!! current_size(%d)>max_available(%d)\n", __FUNCTION__, current_size, max_available);
+		return _FALSE;
+	}
+	return _TRUE;
+}
+
+u8 EfusePgPacketWrite_BT(
+	PADAPTER	pAdapter,
+	u8			offset,
+	u8			word_en,
+	u8			*pData,
+	u8			bPseudoTest)
+{
+	PGPKT_STRUCT targetPkt;
+	u16 startAddr = 0;
+	u8 efuseType = EFUSE_BT;
+
+	if (!hal_BT_EfusePgCheckAvailableAddr(pAdapter, 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;
+}
+
+/*  11/16/2008 MH Add description. Get current efuse area enabled word!!. */
+u8
+Efuse_CalculateWordCnts(IN 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;
+}
+
+/*-----------------------------------------------------------------------------
+ * 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(IN	u8	word_en,
+			 IN	u8	*sourdata,
+			 IN	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];
+	}
+}
+
+/*-----------------------------------------------------------------------------
+ * 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(
+	IN PADAPTER	pAdapter,
+	IN u8		efuseType,
+	IN BOOLEAN	bPseudoTest)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+	u16	mapLen = 0;
+	u8 *efuse_map = NULL;
+	int err;
+
+	mapLen = EEPROM_MAX_SIZE;
+	efuse_map = pHalData->efuse_eeprom_data;
+	/* efuse default content is 0xFF */
+	_rtw_memset(efuse_map, 0xFF, EEPROM_MAX_SIZE);
+
+	EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, bPseudoTest);
+	if (!mapLen) {
+		RTW_WARN("%s: <ERROR> fail to get efuse size!\n", __FUNCTION__);
+		mapLen = EEPROM_MAX_SIZE;
+	}
+	if (mapLen > EEPROM_MAX_SIZE) {
+		RTW_WARN("%s: <ERROR> size of efuse data(%d) is large than expected(%d)!\n",
+			 __FUNCTION__, mapLen, EEPROM_MAX_SIZE);
+		mapLen = EEPROM_MAX_SIZE;
+	}
+
+	if (pHalData->bautoload_fail_flag == _FALSE) {
+		err = rtw_halmac_read_logical_efuse_map(adapter_to_dvobj(pAdapter), efuse_map, mapLen);
+		if (err)
+			RTW_ERR("%s: <ERROR> fail to get efuse map!\n", __FUNCTION__);
+	}
+
+	rtw_dump_cur_efuse(pAdapter);
+} /* EFUSE_ShadowMapUpdate */
+
+const u8 _mac_hidden_max_bw_to_hal_bw_cap[MAC_HIDDEN_MAX_BW_NUM] = {
+	0,
+	0,
+	(BW_CAP_160M | BW_CAP_80M | BW_CAP_40M | BW_CAP_20M | BW_CAP_10M | BW_CAP_5M),
+	(BW_CAP_5M),
+	(BW_CAP_10M | BW_CAP_5M),
+	(BW_CAP_20M | BW_CAP_10M | BW_CAP_5M),
+	(BW_CAP_40M | BW_CAP_20M | BW_CAP_10M | BW_CAP_5M),
+	(BW_CAP_80M | BW_CAP_40M | BW_CAP_20M | BW_CAP_10M | BW_CAP_5M),
+};
+
+const u8 _mac_hidden_proto_to_hal_proto_cap[MAC_HIDDEN_PROTOCOL_NUM] = {
+	0,
+	0,
+	(PROTO_CAP_11N | PROTO_CAP_11G | PROTO_CAP_11B),
+	(PROTO_CAP_11AC | PROTO_CAP_11N | PROTO_CAP_11G | PROTO_CAP_11B),
+};
+
+u8 mac_hidden_wl_func_to_hal_wl_func(u8 func)
+{
+	u8 wl_func = 0;
+
+	if (func & BIT0)
+		wl_func |= WL_FUNC_MIRACAST;
+	if (func & BIT1)
+		wl_func |= WL_FUNC_P2P;
+	if (func & BIT2)
+		wl_func |= WL_FUNC_TDLS;
+	if (func & BIT3)
+		wl_func |= WL_FUNC_FTM;
+
+	return wl_func;
+}
+
+
+u8 rtw_efuse_file_read(PADAPTER padapter, u8 *filepatch, u8 *buf, u32 len)
+{
+	char *ptmpbuf = NULL, *ptr;
+	u8 val8;
+	u32 count, i, j;
+	int err;
+	u32 bufsize = 4096;
+
+	ptmpbuf = rtw_zmalloc(bufsize);
+	if (ptmpbuf == NULL)
+		return _FALSE;
+
+	count = rtw_retrieve_from_file(filepatch, ptmpbuf, bufsize);
+	if (count <= 100) {
+		rtw_mfree(ptmpbuf, bufsize);
+		RTW_ERR("%s, filepatch %s, size=%d, FAIL!!\n", __FUNCTION__, filepatch, count);
+		return _FALSE;
+	}
+
+	i = 0;
+	j = 0;
+	ptr = ptmpbuf;
+	while ((j < len) && (i < count)) {
+		if (ptmpbuf[i] == '\0')
+			break;
+	
+		ptr = strpbrk(&ptmpbuf[i], " \t\n\r");
+		if (ptr) {
+			if (ptr == &ptmpbuf[i]) {
+				i++;
+				continue;
+			}
+
+			/* Add string terminating null */
+			*ptr = 0;
+		} else {
+			ptr = &ptmpbuf[count-1];
+		}
+
+		err = sscanf(&ptmpbuf[i], "%hhx", &val8);
+		if (err != 1) {
+			RTW_WARN("Something wrong to parse efuse file, string=%s\n", &ptmpbuf[i]);
+		} else {
+			buf[j] = val8;
+			RTW_DBG("i=%d, j=%d, 0x%02x\n", i, j, buf[j]);
+			j++;
+		}
+
+		i = ptr - ptmpbuf + 1;
+	}
+
+	rtw_mfree(ptmpbuf, bufsize);
+	RTW_INFO("%s, filepatch %s, size=%d, done\n", __FUNCTION__, filepatch, count);
+	return _TRUE;
+}
+
+u32 rtw_read_efuse_from_file(const char *path, u8 *buf, int map_size)
+{
+	u32 i;
+	u8 c;
+	u8 temp[3];
+	u8 temp_i;
+	u8 end = _FALSE;
+	u32 ret = _FAIL;
+
+	u8 *file_data = NULL;
+	u32 file_size, read_size, pos = 0;
+	u8 *map = NULL;
+
+	if (rtw_is_file_readable_with_size(path, &file_size) != _TRUE) {
+		RTW_PRINT("%s %s is not readable\n", __func__, path);
+		goto exit;
+	}
+
+	file_data = rtw_vmalloc(file_size);
+	if (!file_data) {
+		RTW_ERR("%s rtw_vmalloc(%d) fail\n", __func__, file_size);
+		goto exit;
+	}
+
+	read_size = rtw_retrieve_from_file(path, file_data, file_size);
+	if (read_size == 0) {
+		RTW_ERR("%s read from %s fail\n", __func__, path);
+		goto exit;
+	}
+
+	map = rtw_vmalloc(map_size);
+	if (!map) {
+		RTW_ERR("%s rtw_vmalloc(%d) fail\n", __func__, map_size);
+		goto exit;
+	}
+	_rtw_memset(map, 0xff, map_size);
+
+	temp[2] = 0; /* end of string '\0' */
+
+	for (i = 0 ; i < map_size ; i++) {
+		temp_i = 0;
+
+		while (1) {
+			if (pos >= read_size) {
+				end = _TRUE;
+				break;
+			}
+			c = file_data[pos++];
+
+			/* bypass spece or eol or null before first hex digit */
+			if (temp_i == 0 && (is_eol(c) == _TRUE || is_space(c) == _TRUE || is_null(c) == _TRUE))
+				continue;
+
+			if (IsHexDigit(c) == _FALSE) {
+				RTW_ERR("%s invalid 8-bit hex format for offset:0x%03x\n", __func__, i);
+				goto exit;
+			}
+
+			temp[temp_i++] = c;
+
+			if (temp_i == 2) {
+				/* parse value */
+				if (sscanf(temp, "%hhx", &map[i]) != 1) {
+					RTW_ERR("%s sscanf fail for offset:0x%03x\n", __func__, i);
+					goto exit;
+				}
+				break;
+			}
+		}
+
+		if (end == _TRUE) {
+			if (temp_i != 0) {
+				RTW_ERR("%s incomplete 8-bit hex format for offset:0x%03x\n", __func__, i);
+				goto exit;
+			}
+			break;
+		}
+	}
+
+	RTW_PRINT("efuse file:%s, 0x%03x byte content read\n", path, i);
+
+	_rtw_memcpy(buf, map, map_size);
+
+	ret = _SUCCESS;
+
+exit:
+	if (file_data)
+		rtw_vmfree(file_data, file_size);
+	if (map)
+		rtw_vmfree(map, map_size);
+
+	return ret;
+}
+
+u32 rtw_read_macaddr_from_file(const char *path, u8 *buf)
+{
+	u32 i;
+	u8 temp[3];
+	u32 ret = _FAIL;
+
+	u8 file_data[17];
+	u32 read_size, pos = 0;
+	u8 addr[ETH_ALEN];
+
+	if (rtw_is_file_readable(path) != _TRUE) {
+		RTW_PRINT("%s %s is not readable\n", __func__, path);
+		goto exit;
+	}
+
+	read_size = rtw_retrieve_from_file(path, file_data, 17);
+	if (read_size != 17) {
+		RTW_ERR("%s read from %s fail\n", __func__, path);
+		goto exit;
+	}
+
+	temp[2] = 0; /* end of string '\0' */
+
+	for (i = 0 ; i < ETH_ALEN ; i++) {
+		if (IsHexDigit(file_data[i * 3]) == _FALSE || IsHexDigit(file_data[i * 3 + 1]) == _FALSE) {
+			RTW_ERR("%s invalid 8-bit hex format for address offset:%u\n", __func__, i);
+			goto exit;
+		}
+
+		if (i < ETH_ALEN - 1 && file_data[i * 3 + 2] != ':') {
+			RTW_ERR("%s invalid separator after address offset:%u\n", __func__, i);
+			goto exit;
+		}
+
+		temp[0] = file_data[i * 3];
+		temp[1] = file_data[i * 3 + 1];
+		if (sscanf(temp, "%hhx", &addr[i]) != 1) {
+			RTW_ERR("%s sscanf fail for address offset:0x%03x\n", __func__, i);
+			goto exit;
+		}
+	}
+
+	_rtw_memcpy(buf, addr, ETH_ALEN);
+
+	RTW_PRINT("wifi_mac file: %s\n", path);
+	RTW_INFO(MAC_FMT"\n", MAC_ARG(buf));
+
+	ret = _SUCCESS;
+
+exit:
+	return ret;
+}
+
diff --git a/drivers/staging/rtl8821ce/core/rtw_ap.c b/drivers/staging/rtl8821ce/core/rtw_ap.c
new file mode 100644
index 000000000000..48448aa28fc0
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/rtw_ap.c
@@ -0,0 +1,3263 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * 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 <drv_types.h>
+#include <hal_data.h>
+
+
+extern unsigned char	RTW_WPA_OUI[];
+extern unsigned char	WMM_OUI[];
+extern unsigned char	WPS_OUI[];
+extern unsigned char	P2P_OUI[];
+extern unsigned char	WFD_OUI[];
+
+void init_mlme_ap_info(_adapter *padapter)
+{
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	_rtw_spinlock_init(&pmlmepriv->bcn_update_lock);
+
+	/* pmlmeext->bstart_bss = _FALSE; */
+
+}
+
+void free_mlme_ap_info(_adapter *padapter)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	stop_ap_mode(padapter);
+	_rtw_spinlock_free(&pmlmepriv->bcn_update_lock);
+
+}
+
+static void update_BCNTIM(_adapter *padapter)
+{
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork_mlmeext = &(pmlmeinfo->network);
+	unsigned char *pie = pnetwork_mlmeext->IEs;
+
+	if (_TRUE) {
+		u8 *p, *dst_ie, *premainder_ie = NULL, *pbackup_remainder_ie = NULL;
+		u16 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 = (sint)(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_;
+
+			/* get ssid_ie len */
+			p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SSID_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_));
+			if (p != NULL)
+				offset += tmp_len + 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)
+				_rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+		}
+
+		*dst_ie++ = _TIM_IE_;
+
+		if ((pstapriv->tim_bitmap & 0xff00) && (pstapriv->tim_bitmap & 0x00fe))
+			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) {
+			u8 pvb = 0;
+
+			if (pstapriv->tim_bitmap & 0x00fe)
+				pvb = (u8)tim_bitmap_le;
+			else if (pstapriv->tim_bitmap & 0xff00)
+				pvb = (u8)(tim_bitmap_le >> 8);
+			else
+				pvb = (u8)tim_bitmap_le;
+
+			*dst_ie++ = pvb;
+
+		} else if (tim_ielen == 5) {
+			_rtw_memcpy(dst_ie, &tim_bitmap_le, 2);
+			dst_ie += 2;
+		}
+
+		/*copy remainder IE*/
+		if (pbackup_remainder_ie) {
+			_rtw_memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+			rtw_mfree(pbackup_remainder_ie, remainder_ielen);
+		}
+
+		offset = (uint)(dst_ie - pie);
+		pnetwork_mlmeext->IELength = offset + remainder_ielen;
+
+	}
+}
+
+void rtw_add_bcn_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 index, u8 *data, u8 len)
+{
+	PNDIS_802_11_VARIABLE_IEs	pIE;
+	u8	bmatch = _FALSE;
+	u8	*pie = pnetwork->IEs;
+	u8	*p = NULL, *dst_ie = NULL, *premainder_ie = NULL, *pbackup_remainder_ie = NULL;
+	u32	i, offset, ielen, ie_offset, remainder_ielen = 0;
+
+	for (i = sizeof(NDIS_802_11_FIXED_IEs); i < pnetwork->IELength;) {
+		pIE = (PNDIS_802_11_VARIABLE_IEs)(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 = (sint)(p - pie);
+
+		remainder_ielen = pnetwork->IELength - ie_offset - ielen;
+
+		if (bmatch)
+			dst_ie = p;
+		else
+			dst_ie = (p + ielen);
+	}
+
+	if (dst_ie == NULL)
+		return;
+
+	if (remainder_ielen > 0) {
+		pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+		if (pbackup_remainder_ie && premainder_ie)
+			_rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+	}
+
+	*dst_ie++ = index;
+	*dst_ie++ = len;
+
+	_rtw_memcpy(dst_ie, data, len);
+	dst_ie += len;
+
+	/* copy remainder IE */
+	if (pbackup_remainder_ie) {
+		_rtw_memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+		rtw_mfree(pbackup_remainder_ie, remainder_ielen);
+	}
+
+	offset = (uint)(dst_ie - pie);
+	pnetwork->IELength = offset + remainder_ielen;
+}
+
+void rtw_remove_bcn_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 index)
+{
+	u8 *p, *dst_ie = NULL, *premainder_ie = NULL, *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 = (sint)(p - pie);
+
+		remainder_ielen = pnetwork->IELength - ie_offset - ielen;
+
+		dst_ie = p;
+	} else
+		return;
+
+	if (remainder_ielen > 0) {
+		pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+		if (pbackup_remainder_ie && premainder_ie)
+			_rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+	}
+
+	/* copy remainder IE */
+	if (pbackup_remainder_ie) {
+		_rtw_memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+		rtw_mfree(pbackup_remainder_ie, remainder_ielen);
+	}
+
+	offset = (uint)(dst_ie - pie);
+	pnetwork->IELength = offset + remainder_ielen;
+}
+
+u8 chk_sta_is_alive(struct sta_info *psta);
+u8 chk_sta_is_alive(struct sta_info *psta)
+{
+	u8 ret = _FALSE;
+
+	/* if(sta_last_rx_pkts(psta) == sta_rx_pkts(psta)) */
+	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(_adapter *padapter)
+{
+	_irqL irqL;
+	_list	*phead, *plist;
+	u8 updated = _FALSE;
+	struct sta_info *psta = NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 chk_alive_num = 0;
+	char chk_alive_list[NUM_STA];
+	int i;
+
+	_enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
+
+	phead = &pstapriv->auth_list;
+	plist = get_next(phead);
+
+	/* check auth_queue */
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+		psta = LIST_CONTAINOR(plist, struct sta_info, auth_list);
+
+		plist = get_next(plist);
+
+		if (psta->expire_to > 0) {
+			psta->expire_to--;
+			if (psta->expire_to == 0) {
+				rtw_list_delete(&psta->auth_list);
+				pstapriv->auth_list_cnt--;
+
+				RTW_INFO("auth expire %02X%02X%02X%02X%02X%02X\n",
+					psta->hwaddr[0], psta->hwaddr[1], psta->hwaddr[2], psta->hwaddr[3], psta->hwaddr[4], psta->hwaddr[5]);
+
+				_exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
+
+				/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);	 */
+				rtw_free_stainfo(padapter, psta);
+				/* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);	 */
+
+				_enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
+			}
+		}
+
+	}
+
+	_exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
+	psta = NULL;
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+
+	/* check asoc_queue */
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		plist = get_next(plist);
+		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 staion is at ps mode.					 */
+					psta->expire_to = pstapriv->expire_to;
+					psta->state |= WIFI_STA_ALIVE_CHK_STATE;
+
+					/* RTW_INFO("alive chk, sta:" MAC_FMT " is at ps mode!\n", MAC_ARG(psta->hwaddr)); */
+
+					/* to update bcn with tim_bitmap for this station */
+					pstapriv->tim_bitmap |= BIT(psta->aid);
+					update_beacon(padapter, _TIM_IE_, NULL, _TRUE);
+
+					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;
+			}
+			rtw_list_delete(&psta->asoc_list);
+			pstapriv->asoc_list_cnt--;
+			RTW_INFO("asoc expire "MAC_FMT", state=0x%x\n", MAC_ARG(psta->hwaddr), psta->state);
+			updated = ap_free_sta(padapter, psta, _FALSE, WLAN_REASON_DEAUTH_LEAVING, _TRUE);
+		} 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)
+			   ) {
+				RTW_INFO("%s sta:"MAC_FMT", sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", __func__
+					 , MAC_ARG(psta->hwaddr)
+					, psta->sleepq_len, padapter->xmitpriv.free_xmitframe_cnt, pstapriv->asoc_list_cnt);
+				wakeup_sta_to_xmit(padapter, psta);
+			}
+		}
+	}
+
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	if (chk_alive_num) {
+
+		u8 backup_ch = 0, backup_bw, backup_offset;
+		u8 union_ch = 0, union_bw, union_offset;
+		u8 switch_channel = _TRUE;
+		struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+		if (!rtw_mi_get_ch_setting_union(padapter, &union_ch, &union_bw, &union_offset)
+			|| pmlmeext->cur_channel != union_ch)
+			goto bypass_active_keep_alive;
+
+		/* switch to correct channel of current network  before issue keep-alive frames */
+		if (switch_channel == _TRUE && rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) {
+			backup_ch = rtw_get_oper_ch(padapter);
+			backup_bw = rtw_get_oper_bw(padapter);
+			backup_offset = rtw_get_oper_choffset(padapter);
+			set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
+		}
+
+		/* 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 & _FW_LINKED))
+				continue;
+
+			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) {
+				RTW_INFO("asoc check, sta(" MAC_FMT ") is alive\n", MAC_ARG(psta->hwaddr));
+				psta->expire_to = pstapriv->expire_to;
+				psta->keep_alive_trycnt = 0;
+				continue;
+			} else if (psta->keep_alive_trycnt <= 3) {
+				RTW_INFO("ack check for asoc expire, keep_alive_trycnt=%d\n", psta->keep_alive_trycnt);
+				psta->expire_to = 1;
+				continue;
+			}
+
+			psta->keep_alive_trycnt = 0;
+			RTW_INFO("asoc expire "MAC_FMT", state=0x%x\n", MAC_ARG(psta->hwaddr), psta->state);
+			_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+			if (rtw_is_list_empty(&psta->asoc_list) == _FALSE) {
+				rtw_list_delete(&psta->asoc_list);
+				pstapriv->asoc_list_cnt--;
+				updated = ap_free_sta(padapter, psta, _FALSE, WLAN_REASON_DEAUTH_LEAVING, _TRUE);
+			}
+			_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+		}
+
+		/* back to the original operation channel */
+		if (switch_channel && backup_ch > 0)
+			set_channel_bwmode(padapter, backup_ch, backup_offset, backup_bw);
+
+bypass_active_keep_alive:
+		;
+	}
+
+	associated_clients_update(padapter, updated, STA_INFO_UPDATE_ALL);
+}
+
+void add_RATid(_adapter *padapter, struct sta_info *psta, u8 rssi_level, u8 is_update_bw)
+{
+	int i;
+	u8 rf_type;
+	unsigned char sta_band = 0;
+	u64 tx_ra_bitmap = 0;
+	struct ht_priv	*psta_ht = NULL;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	WLAN_BSSID_EX *pcur_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network;
+
+	if (psta)
+		psta_ht = &psta->htpriv;
+	else
+		return;
+
+	if (!(psta->state & _FW_LINKED))
+		return;
+
+	rtw_hal_update_sta_rate_mask(padapter, psta);
+	tx_ra_bitmap = psta->ra_mask;
+
+	if (pcur_network->Configuration.DSConfig > 14) {
+
+		if (tx_ra_bitmap & 0xffff000)
+			sta_band |= WIRELESS_11_5N ;
+
+		if (tx_ra_bitmap & 0xff0)
+			sta_band |= WIRELESS_11A;
+
+		/* 5G band */
+		if (psta->vhtpriv.vht_option)
+			sta_band = WIRELESS_11_5AC;
+
+	} else {
+		if (tx_ra_bitmap & 0xffff000)
+			sta_band |= WIRELESS_11_24N;
+
+		if (tx_ra_bitmap & 0xff0)
+			sta_band |= WIRELESS_11G;
+
+		if (tx_ra_bitmap & 0x0f)
+			sta_band |= WIRELESS_11B;
+	}
+
+	psta->wireless_mode = sta_band;
+	psta->raid = rtw_hal_networktype_to_raid(padapter, psta);
+
+	if (psta->aid < NUM_STA) {
+		RTW_INFO("%s=> mac_id:%d , raid:%d, tx_ra_bitmap:0x%016llx, networkType:0x%02x\n",
+			__FUNCTION__, psta->mac_id, psta->raid, tx_ra_bitmap, psta->wireless_mode);
+
+		rtw_update_ramask(padapter, psta, psta->mac_id, rssi_level, is_update_bw);
+	} else
+		RTW_INFO("station aid %d exceed the max number\n", psta->aid);
+
+}
+
+void update_bmc_sta(_adapter *padapter)
+{
+	_irqL	irqL;
+	unsigned char	network_type;
+	int supportRateNum = 0;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	WLAN_BSSID_EX *pcur_network = (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->qos_option = 0;
+		psta->htpriv.ht_option = _FALSE;
+
+		psta->ieee8021x_blocked = 0;
+
+		_rtw_memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
+
+		/* psta->dot118021XPrivacy = _NO_PRIVACY_; */ /* !!! remove it, because it has been set before this. */
+
+		/* prepare for add_RATid		 */
+		supportRateNum = rtw_get_rateset_len((u8 *)&pcur_network->SupportedRates);
+		network_type = rtw_check_network_type((u8 *)&pcur_network->SupportedRates, supportRateNum, pcur_network->Configuration.DSConfig);
+		if (IsSupportedTxCCK(network_type))
+			network_type = WIRELESS_11B;
+		else if (network_type == WIRELESS_INVALID) { /* error handling */
+			if (pcur_network->Configuration.DSConfig > 14)
+				network_type = WIRELESS_11A;
+			else
+				network_type = WIRELESS_11B;
+		}
+		update_sta_basic_rate(psta, network_type);
+		psta->wireless_mode = network_type;
+
+		rtw_hal_update_sta_rate_mask(padapter, psta);
+
+		psta->raid = rtw_hal_networktype_to_raid(padapter, psta);
+
+		_enter_critical_bh(&psta->lock, &irqL);
+		psta->state = _FW_LINKED;
+		_exit_critical_bh(&psta->lock, &irqL);
+
+		rtw_sta_media_status_rpt(padapter, psta, 1);
+		rtw_hal_update_ra_mask(psta, psta->rssi_level, _TRUE);
+	} else
+		RTW_INFO("add_RATid_bmc_sta error!\n");
+
+}
+
+/* notes:
+ * AID: 1~MAX for sta and 0 for bc/mc in ap/adhoc mode  */
+void update_sta_info_apmode(_adapter *padapter, struct sta_info *psta)
+{
+	_irqL	irqL;
+	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;
+	u8	cur_ldpc_cap = 0, cur_stbc_cap = 0, cur_beamform_cap = 0;
+	/* set intf_tag to if1 */
+	/* psta->intf_tag = 0; */
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	/*alloc macid when call rtw_alloc_stainfo(),release macid when call rtw_free_stainfo()*/
+
+	/* 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;
+
+		phtpriv_sta->rx_ampdu_min_spacing = (phtpriv_sta->ht_cap.ampdu_params_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2;
+
+		/* bwmode */
+		if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH))
+			psta->bw_mode = CHANNEL_WIDTH_40;
+		else
+			psta->bw_mode = CHANNEL_WIDTH_20;
+
+		if (psta->ht_40mhz_intolerant)
+			psta->bw_mode = CHANNEL_WIDTH_20;
+
+		if (pmlmeext->cur_bwmode < psta->bw_mode)
+			psta->bw_mode = pmlmeext->cur_bwmode;
+
+		phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset;
+
+		/* check if sta support s Short GI 20M */
+		if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_20))
+			phtpriv_sta->sgi_20m = _TRUE;
+
+		/* check if sta support s Short GI 40M */
+		if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_40)) {
+			if (psta->bw_mode == CHANNEL_WIDTH_40) /* according to psta->bw_mode */
+				phtpriv_sta->sgi_40m = _TRUE;
+			else
+				phtpriv_sta->sgi_40m = _FALSE;
+		}
+
+		psta->qos_option = _TRUE;
+
+		/* B0 Config LDPC Coding Capability */
+		if (TEST_FLAG(phtpriv_ap->ldpc_cap, LDPC_HT_ENABLE_TX) &&
+		    GET_HT_CAP_ELE_LDPC_CAP((u8 *)(&phtpriv_sta->ht_cap))) {
+			SET_FLAG(cur_ldpc_cap, (LDPC_HT_ENABLE_TX | LDPC_HT_CAP_TX));
+			RTW_INFO("Enable HT Tx LDPC for STA(%d)\n", psta->aid);
+		}
+
+		/* B7 B8 B9 Config STBC setting */
+		if (TEST_FLAG(phtpriv_ap->stbc_cap, STBC_HT_ENABLE_TX) &&
+		    GET_HT_CAP_ELE_RX_STBC((u8 *)(&phtpriv_sta->ht_cap))) {
+			SET_FLAG(cur_stbc_cap, (STBC_HT_ENABLE_TX | STBC_HT_CAP_TX));
+			RTW_INFO("Enable HT Tx STBC for STA(%d)\n", psta->aid);
+		}
+
+	} else {
+		phtpriv_sta->ampdu_enable = _FALSE;
+
+		phtpriv_sta->sgi_20m = _FALSE;
+		phtpriv_sta->sgi_40m = _FALSE;
+		psta->bw_mode = CHANNEL_WIDTH_20;
+		phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	}
+
+	phtpriv_sta->ldpc_cap = cur_ldpc_cap;
+	phtpriv_sta->stbc_cap = cur_stbc_cap;
+	phtpriv_sta->beamform_cap = cur_beamform_cap;
+
+	/* 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 */
+
+	update_sta_vht_info_apmode(padapter, psta);
+
+	update_ldpc_stbc_cap(psta);
+
+	/* todo: init other variables */
+
+	_rtw_memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
+
+	/* add ratid */
+	/* add_RATid(padapter, psta); */ /* move to ap_sta_info_defer_update() */
+
+	_enter_critical_bh(&psta->lock, &irqL);
+	psta->state |= _FW_LINKED;
+	_exit_critical_bh(&psta->lock, &irqL);
+
+}
+
+static void update_ap_info(_adapter *padapter, struct sta_info *psta)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network;
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct ht_priv	*phtpriv_ap = &pmlmepriv->htpriv;
+
+	psta->wireless_mode = pmlmeext->cur_wireless_mode;
+
+	psta->bssratelen = rtw_get_rateset_len(pnetwork->SupportedRates);
+	_rtw_memcpy(psta->bssrateset, pnetwork->SupportedRates, psta->bssratelen);
+
+	/* HT related cap */
+	if (phtpriv_ap->ht_option) {
+		/* check if sta supports rx ampdu */
+		/* phtpriv_ap->ampdu_enable = phtpriv_ap->ampdu_enable; */
+
+		/* check if sta support s Short GI 20M */
+		if ((phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_20))
+			phtpriv_ap->sgi_20m = _TRUE;
+		/* check if sta support s Short GI 40M */
+		if ((phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_40))
+			phtpriv_ap->sgi_40m = _TRUE;
+
+		psta->qos_option = _TRUE;
+	} else {
+		phtpriv_ap->ampdu_enable = _FALSE;
+
+		phtpriv_ap->sgi_20m = _FALSE;
+		phtpriv_ap->sgi_40m = _FALSE;
+	}
+
+	psta->bw_mode = pmlmeext->cur_bwmode;
+	phtpriv_ap->ch_offset = pmlmeext->cur_ch_offset;
+
+	phtpriv_ap->agg_enable_bitmap = 0x0;/* reset */
+	phtpriv_ap->candidate_tid_bitmap = 0x0;/* reset */
+
+	_rtw_memcpy(&psta->htpriv, &pmlmepriv->htpriv, sizeof(struct ht_priv));
+
+	_rtw_memcpy(&psta->vhtpriv, &pmlmepriv->vhtpriv, sizeof(struct vht_priv));
+
+
+	psta->state |= WIFI_AP_STATE; /* Aries, add,fix bug of flush_cam_entry at STOP AP mode , 0724 */
+}
+
+static void rtw_set_hw_wmm_param(_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;
+
+	acm_mask = 0;
+
+	if (is_supported_5g(pmlmeext->cur_wireless_mode) ||
+	    (pmlmeext->cur_wireless_mode & WIRELESS_11_24N))
+		aSifsTime = 16;
+	else
+		aSifsTime = 10;
+
+	if (pmlmeinfo->WMM_enable == 0) {
+		padapter->mlmepriv.acm_mask = 0;
+
+		AIFS = aSifsTime + (2 * pmlmeinfo->slotTime);
+
+		if (pmlmeext->cur_wireless_mode & (WIRELESS_11G | WIRELESS_11A)) {
+			ECWMin = 4;
+			ECWMax = 10;
+		} else if (pmlmeext->cur_wireless_mode & WIRELESS_11B) {
+			ECWMin = 5;
+			ECWMax = 10;
+		} else {
+			ECWMin = 4;
+			ECWMax = 10;
+		}
+
+		TXOP = 0;
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm));
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm));
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm));
+
+		ECWMin = 2;
+		ECWMax = 3;
+		TXOP = 0x2f;
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm));
+
+	} else {
+		edca[0] = edca[1] = edca[2] = edca[3] = 0;
+
+		/*TODO:*/
+		acm_mask = 0;
+		padapter->mlmepriv.acm_mask = acm_mask;
+
+		AIFS = (7 * pmlmeinfo->slotTime) + aSifsTime;
+		ECWMin = 4;
+		ECWMax = 10;
+		TXOP = 0;
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm));
+		edca[XMIT_BK_QUEUE] = acParm;
+		RTW_INFO("WMM(BK): %x\n", acParm);
+
+		/* BE */
+		AIFS = (3 * pmlmeinfo->slotTime) + aSifsTime;
+		ECWMin = 4;
+		ECWMax = 6;
+		TXOP = 0;
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm));
+		edca[XMIT_BE_QUEUE] = acParm;
+		RTW_INFO("WMM(BE): %x\n", acParm);
+
+		/* VI */
+		AIFS = (1 * pmlmeinfo->slotTime) + aSifsTime;
+		ECWMin = 3;
+		ECWMax = 4;
+		TXOP = 94;
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm));
+		edca[XMIT_VI_QUEUE] = acParm;
+		RTW_INFO("WMM(VI): %x\n", acParm);
+
+		/* VO */
+		AIFS = (1 * pmlmeinfo->slotTime) + aSifsTime;
+		ECWMin = 2;
+		ECWMax = 3;
+		TXOP = 47;
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm));
+		edca[XMIT_VO_QUEUE] = acParm;
+		RTW_INFO("WMM(VO): %x\n", 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];
+			RTW_INFO("wmm_para_seq(%d): %d\n", i, pxmitpriv->wmm_para_seq[i]);
+		}
+
+	}
+
+}
+
+static void update_hw_ht_param(_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);
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	/* 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 = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2;
+	if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) {
+		RTW_INFO("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __FUNCTION__);
+	}
+
+	/*  */
+	/* Config current HT Protection mode. */
+	/*  */
+	/* pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3; */
+
+}
+
+static void rtw_ap_check_scan(_adapter *padapter)
+{
+	_irqL	irqL;
+	_list		*plist, *phead;
+	u32	delta_time, lifetime;
+	struct	wlan_network	*pnetwork = NULL;
+	WLAN_BSSID_EX *pbss = NULL;
+	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	_queue	*queue	= &(pmlmepriv->scanned_queue);
+	u8 do_scan = _FALSE;
+	u8 reason = RTW_AUTO_SCAN_REASON_UNSPECIFIED;
+
+	lifetime = SCANQUEUE_LIFETIME; /* 20 sec */
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+	phead = get_list_head(queue);
+	if (rtw_end_of_queue_search(phead, get_next(phead)) == _TRUE)
+		if (padapter->registrypriv.wifi_spec) {
+			do_scan = _TRUE;
+			reason |= RTW_AUTO_SCAN_REASON_2040_BSS;
+		}
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+
+	if (_TRUE == do_scan) {
+		RTW_INFO("%s : drv scans by itself and wait_completed\n", __func__);
+		rtw_drv_scan_by_self(padapter, reason);
+		rtw_scan_wait_completed(padapter);
+	}
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	while (1) {
+
+		if (rtw_end_of_queue_search(phead, plist) == _TRUE)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+		if (rtw_chset_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0
+		    && rtw_mlme_band_check(padapter, pnetwork->network.Configuration.DSConfig) == _TRUE
+		    && _TRUE == rtw_validate_ssid(&(pnetwork->network.Ssid))) {
+			delta_time = (u32) rtw_get_passing_time_ms(pnetwork->last_scanned);
+
+			if (delta_time < lifetime) {
+
+				uint ie_len = 0;
+				u8 *pbuf = NULL;
+				u8 *ie = NULL;
+
+				pbss = &pnetwork->network;
+				ie = pbss->IEs;
+
+				/*check if HT CAP INFO IE exists or not*/
+				pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pbss->IELength - _BEACON_IE_OFFSET_));
+				if (pbuf == NULL) {
+					/* HT CAP INFO IE don't exist, it is b/g mode bss.*/
+
+					if (_FALSE == ATOMIC_READ(&pmlmepriv->olbc))
+						ATOMIC_SET(&pmlmepriv->olbc, _TRUE);
+
+					if (_FALSE == ATOMIC_READ(&pmlmepriv->olbc_ht))
+						ATOMIC_SET(&pmlmepriv->olbc_ht, _TRUE);
+					
+					if (padapter->registrypriv.wifi_spec)
+						RTW_INFO("%s: %s is a/b/g ap\n", __func__, pnetwork->network.Ssid.Ssid);
+				}
+			}
+		}
+
+		plist = get_next(plist);
+
+	}
+
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	pmlmepriv->num_sta_no_ht = 0; /* reset to 0 after ap do scanning*/
+
+}
+
+void rtw_start_bss_hdl_after_chbw_decided(_adapter *adapter)
+{
+	WLAN_BSSID_EX *pnetwork = &(adapter->mlmepriv.cur_network.network);
+	struct sta_info *sta = NULL;
+
+	/* update cur_wireless_mode */
+	update_wireless_mode(adapter);
+
+	/* update RRSR and RTS_INIT_RATE register after set channel and bandwidth */
+	UpdateBrateTbl(adapter, pnetwork->SupportedRates);
+	rtw_hal_set_hwreg(adapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates);
+
+	/* update capability after cur_wireless_mode updated */
+	update_capinfo(adapter, rtw_get_capability(pnetwork));
+
+	/* update bc/mc sta_info */
+	update_bmc_sta(adapter);
+
+	/* update AP's sta info */
+	sta = rtw_get_stainfo(&adapter->stapriv, pnetwork->MacAddress);
+	if (!sta) {
+		RTW_INFO(FUNC_ADPT_FMT" !sta for macaddr="MAC_FMT"\n", FUNC_ADPT_ARG(adapter), MAC_ARG(pnetwork->MacAddress));
+		rtw_warn_on(1);
+		return;
+	}
+
+	update_ap_info(adapter, sta);
+}
+
+void start_bss_network(_adapter *padapter, struct createbss_parm *parm)
+{
+#define DUMP_ADAPTERS_STATUS 0
+
+	u8 val8;
+	u16 bcn_interval;
+	u32	acparm;
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct security_priv *psecuritypriv = &(padapter->securitypriv);
+	WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; /* used as input */
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork_mlmeext = &(pmlmeinfo->network);
+	struct dvobj_priv *pdvobj = padapter->dvobj;
+	s16 req_ch = -1, req_bw = -1, req_offset = -1;
+	bool ch_setting_changed = _FALSE;
+	u8 ch_to_set = 0, bw_to_set, offset_to_set;
+	u8 doiqk = _FALSE;
+	/* use for check ch bw offset can be allowed or not */
+	u8 chbw_allow = _TRUE;
+
+	if (parm->req_ch != 0) {
+		/* bypass other setting, go checking ch, bw, offset */
+		req_ch = parm->req_ch;
+		req_bw = parm->req_bw;
+		req_offset = parm->req_offset;
+		goto chbw_decision;
+	} else {
+		/* inform this request comes from upper layer */
+		req_ch = 0;
+	}
+
+	bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod;
+
+	/* 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 (NULL == 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 */
+	/* pmlmeinfo->WMM_enable; */
+	/* pmlmeinfo->HT_enable; */
+	if (pmlmepriv->qospriv.qos_option)
+		pmlmeinfo->WMM_enable = _TRUE;
+	if (pmlmepriv->htpriv.ht_option) {
+		pmlmeinfo->WMM_enable = _TRUE;
+		pmlmeinfo->HT_enable = _TRUE;
+		/* pmlmeinfo->HT_info_enable = _TRUE; */
+		/* pmlmeinfo->HT_caps_enable = _TRUE; */
+
+		update_hw_ht_param(padapter);
+	}
+
+	if (pmlmepriv->vhtpriv.vht_option) {
+		pmlmeinfo->VHT_enable = _TRUE;
+		update_hw_vht_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 = 0x00105320; */ /* BE */
+	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));
+
+chbw_decision:
+	ch_setting_changed = rtw_ap_chbw_decision(padapter, req_ch, req_bw, req_offset
+		     , &ch_to_set, &bw_to_set, &offset_to_set, &chbw_allow);
+
+	/* let pnetwork_mlmeext == pnetwork_mlme. */
+	_rtw_memcpy(pnetwork_mlmeext, pnetwork, pnetwork->Length);
+
+	rtw_start_bss_hdl_after_chbw_decided(padapter);
+
+
+	doiqk = _TRUE;
+	rtw_hal_set_hwreg(padapter , HW_VAR_DO_IQK , &doiqk);
+
+	if (ch_to_set != 0) {
+		set_channel_bwmode(padapter, ch_to_set, offset_to_set, bw_to_set);
+		rtw_mi_update_union_chan_inf(padapter, ch_to_set, offset_to_set, bw_to_set);
+	}
+
+	doiqk = _FALSE;
+	rtw_hal_set_hwreg(padapter , HW_VAR_DO_IQK , &doiqk);
+
+	if (DUMP_ADAPTERS_STATUS) {
+		RTW_INFO(FUNC_ADPT_FMT" done\n", FUNC_ADPT_ARG(padapter));
+		dump_adapters_status(RTW_DBGDUMP , adapter_to_dvobj(padapter));
+	}
+
+	/* update beacon content only if bstart_bss is _TRUE */
+	if (_TRUE == pmlmeext->bstart_bss) {
+
+		_irqL irqL;
+
+		if ((ATOMIC_READ(&pmlmepriv->olbc) == _TRUE) || (ATOMIC_READ(&pmlmepriv->olbc_ht) == _TRUE)) {
+			/* AP is not starting a 40 MHz BSS in presence of an 802.11g BSS. */
+
+			pmlmepriv->ht_op_mode &= (~HT_INFO_OPERATION_MODE_OP_MODE_MASK);
+			pmlmepriv->ht_op_mode |= OP_MODE_MAY_BE_LEGACY_STAS;
+			update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _FALSE);
+		}
+
+		update_beacon(padapter, _TIM_IE_, NULL, _FALSE);
+
+
+	}
+
+	rtw_scan_wait_completed(padapter);
+
+	/* send beacon */
+	if (!rtw_mi_check_fwstate(padapter, _FW_UNDER_SURVEY)) {
+
+		/*update_beacon(padapter, _TIM_IE_, NULL, _TRUE);*/
+	}
+
+	/*Set EDCA param reg after update cur_wireless_mode & update_capinfo*/
+	if (pregpriv->wifi_spec == 1)
+		rtw_set_hw_wmm_param(padapter);
+
+	/*pmlmeext->bstart_bss = _TRUE;*/
+}
+
+int rtw_check_beacon_data(_adapter *padapter, u8 *pbuf,  int len)
+{
+	int ret = _SUCCESS;
+	u8 *p;
+	u8 *pHT_caps_ie = NULL;
+	u8 *pHT_info_ie = 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 wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+	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);
+	WLAN_BSSID_EX *pbss_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 *ie = pbss_network->IEs;
+	u8 vht_cap = _FALSE;
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 rf_num = 0;
+
+	/* 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 */
+
+	RTW_INFO("%s, len=%d\n", __FUNCTION__, len);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE)
+		return _FAIL;
+
+	if (len > MAX_IE_SZ)
+		return _FAIL;
+
+	pbss_network->IELength = len;
+
+	_rtw_memset(ie, 0, MAX_IE_SZ);
+
+	_rtw_memcpy(ie, pbuf, pbss_network->IELength);
+
+	if (pbss_network->InfrastructureMode != Ndis802_11APMode)
+		return _FAIL;
+
+	rtw_ap_check_scan(padapter);
+
+	pbss_network->Rssi = 0;
+
+	_rtw_memcpy(pbss_network->MacAddress, adapter_mac_addr(padapter), ETH_ALEN);
+
+	/* beacon interval */
+	p = rtw_get_beacon_interval_from_ie(ie);/* ie + 8;	 */ /* 8: TimeStamp, 2: Beacon Interval 2:Capability */
+	/* pbss_network->Configuration.BeaconPeriod = le16_to_cpu(*(unsigned short*)p); */
+	pbss_network->Configuration.BeaconPeriod = RTW_GET_LE16(p);
+
+	/* capability */
+	/* cap = *(unsigned short *)rtw_get_capability_from_ie(ie); */
+	/* cap = le16_to_cpu(cap); */
+	cap = RTW_GET_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) {
+		_rtw_memset(&pbss_network->Ssid, 0, sizeof(NDIS_802_11_SSID));
+		_rtw_memcpy(pbss_network->Ssid.Ssid, (p + 2), ie_len);
+		pbss_network->Ssid.SsidLength = ie_len;
+		_rtw_memcpy(padapter->wdinfo.p2p_group_ssid, pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength);
+		padapter->wdinfo.p2p_group_ssid_len = pbss_network->Ssid.SsidLength;
+	}
+
+	/* chnnel */
+	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;
+
+	_rtw_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) {
+		_rtw_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) {
+		_rtw_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, (PNDIS_802_11_VARIABLE_IEs)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) && (_rtw_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) && _rtw_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 = 0;
+		HT_CAP_AMPDU_FACTOR max_rx_ampdu_factor = MAX_AMPDU_FACTOR_64K;
+		struct rtw_ieee80211_ht_cap *pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2);
+
+		if (0) {
+			RTW_INFO(FUNC_ADPT_FMT" HT_CAP_IE from upper layer:\n", FUNC_ADPT_ARG(padapter));
+			dump_ht_cap_ie_content(RTW_DBGDUMP, p + 2, ie_len);
+		}
+
+		pHT_caps_ie = p;
+
+		ht_cap = _TRUE;
+		network_type |= WIRELESS_11_24N;
+
+		rtw_ht_use_default_setting(padapter);
+
+		/* Update HT Capabilities Info field */
+		if (pmlmepriv->htpriv.sgi_20m == _FALSE)
+			pht_cap->cap_info &= ~(IEEE80211_HT_CAP_SGI_20);
+
+		if (pmlmepriv->htpriv.sgi_40m == _FALSE)
+			pht_cap->cap_info &= ~(IEEE80211_HT_CAP_SGI_40);
+
+		if (!TEST_FLAG(pmlmepriv->htpriv.ldpc_cap, LDPC_HT_ENABLE_RX))
+			pht_cap->cap_info &= ~(IEEE80211_HT_CAP_LDPC_CODING);
+
+		if (!TEST_FLAG(pmlmepriv->htpriv.stbc_cap, STBC_HT_ENABLE_TX))
+			pht_cap->cap_info &= ~(IEEE80211_HT_CAP_TX_STBC);
+
+		if (!TEST_FLAG(pmlmepriv->htpriv.stbc_cap, STBC_HT_ENABLE_RX))
+			pht_cap->cap_info &= ~(IEEE80211_HT_CAP_RX_STBC_3R);
+
+		/* Update A-MPDU Parameters field */
+		pht_cap->ampdu_params_info &= ~(IEEE80211_HT_CAP_AMPDU_FACTOR | IEEE80211_HT_CAP_AMPDU_DENSITY);
+
+		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);
+
+		rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor);
+		pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_FACTOR & max_rx_ampdu_factor); /* set  Max Rx AMPDU size  to 64K */
+
+		_rtw_memcpy(&(pmlmeinfo->HT_caps), pht_cap, sizeof(struct HT_caps_element));
+
+		/* Update Supported MCS Set field */
+		{
+			struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter);
+			u8 rx_nss = 0;
+			int i;
+
+			rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+			rx_nss = rtw_min(rf_type_to_rf_rx_cnt(rf_type), hal_spec->rx_nss_num);
+
+			/* RX MCS Bitmask */
+			switch (rx_nss) {
+			case 1:
+				set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_1R);
+				break;
+			case 2:
+				set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_2R);
+				break;
+			case 3:
+				set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_3R);
+				break;
+			case 4:
+				set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_4R);
+				break;
+			default:
+				RTW_WARN("rf_type:%d or rx_nss:%u is not expected\n", rf_type, hal_spec->rx_nss_num);
+			}
+			for (i = 0; i < 10; i++)
+				*(HT_CAP_ELE_RX_MCS_MAP(pht_cap) + i) &= padapter->mlmeextpriv.default_supported_mcs_set[i];
+		}
+
+
+		_rtw_memcpy(&pmlmepriv->htpriv.ht_cap, p + 2, ie_len);
+
+		if (0) {
+			RTW_INFO(FUNC_ADPT_FMT" HT_CAP_IE driver masked:\n", FUNC_ADPT_ARG(padapter));
+			dump_ht_cap_ie_content(RTW_DBGDUMP, 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 == _TRUE) {
+		pmlmepriv->htpriv.ht_option = _TRUE;
+		pmlmepriv->qospriv.qos_option = 1;
+
+		pmlmepriv->htpriv.ampdu_enable = pregistrypriv->ampdu_enable ? _TRUE : _FALSE;
+
+		HT_caps_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)pHT_caps_ie);
+
+		HT_info_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)pHT_info_ie);
+	}
+
+
+	/* Parsing VHT CAP IE */
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, EID_VHTCapability, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if (p && ie_len > 0)
+		vht_cap = _TRUE;
+	/* Parsing VHT OPERATION IE */
+
+	pmlmepriv->vhtpriv.vht_option = _FALSE;
+	/* if channel in 5G band, then add vht ie . */
+	if ((pbss_network->Configuration.DSConfig > 14)
+	    && (pmlmepriv->htpriv.ht_option == _TRUE)
+	    && REGSTY_IS_11AC_ENABLE(pregistrypriv)
+	    && hal_chk_proto_cap(padapter, PROTO_CAP_11AC)
+	    && (!pmlmepriv->country_ent || COUNTRY_CHPLAN_EN_11AC(pmlmepriv->country_ent))
+	   ) {
+		if (vht_cap == _TRUE)
+			pmlmepriv->vhtpriv.vht_option = _TRUE;
+		else if (REGSTY_IS_11AC_AUTO(pregistrypriv)) {
+			u8	cap_len, operation_len;
+
+			rtw_vht_use_default_setting(padapter);
+
+			{
+				/* VHT Operation mode notifiy bit in Extended IE (127) */
+				uint len = 0;
+
+				SET_EXT_CAPABILITY_ELE_OP_MODE_NOTIF(pmlmepriv->ext_capab_ie_data, 1);
+				pmlmepriv->ext_capab_ie_len = 10;
+				rtw_set_ie(pbss_network->IEs + pbss_network->IELength, EID_EXTCapability, 8, pmlmepriv->ext_capab_ie_data, &len);
+				pbss_network->IELength += pmlmepriv->ext_capab_ie_len;
+			}
+
+			/* VHT Capabilities element */
+			cap_len = rtw_build_vht_cap_ie(padapter, pbss_network->IEs + pbss_network->IELength);
+			pbss_network->IELength += cap_len;
+
+			/* VHT Operation element */
+			operation_len = rtw_build_vht_operation_ie(padapter, pbss_network->IEs + pbss_network->IELength, pbss_network->Configuration.DSConfig);
+			pbss_network->IELength += operation_len;
+
+			pmlmepriv->vhtpriv.vht_option = _TRUE;
+		}
+	}
+
+	if(pbss_network->Configuration.DSConfig <= 14 && padapter->registrypriv.wifi_spec == 1) {
+		uint len = 0;
+
+		SET_EXT_CAPABILITY_ELE_BSS_COEXIST(pmlmepriv->ext_capab_ie_data, 1);
+		pmlmepriv->ext_capab_ie_len = 10;
+		rtw_set_ie(pbss_network->IEs + pbss_network->IELength, EID_EXTCapability, 8, pmlmepriv->ext_capab_ie_data, &len);
+		pbss_network->IELength += pmlmepriv->ext_capab_ie_len;
+	}
+
+	pbss_network->Length = get_WLAN_BSSID_EX_sz((WLAN_BSSID_EX *)pbss_network);
+
+	rtw_ies_get_chbw(pbss_network->IEs + _BEACON_IE_OFFSET_, pbss_network->IELength - _BEACON_IE_OFFSET_
+		, &pmlmepriv->ori_ch, &pmlmepriv->ori_bw, &pmlmepriv->ori_offset);
+	rtw_warn_on(pmlmepriv->ori_ch == 0);
+
+	{
+		/* alloc sta_info for ap itself */
+
+		struct sta_info *sta;
+
+		sta = rtw_get_stainfo(&padapter->stapriv, pbss_network->MacAddress);
+		if (!sta) {
+			sta = rtw_alloc_stainfo(&padapter->stapriv, pbss_network->MacAddress);
+			if (sta == NULL)
+				return _FAIL;
+		}
+	}
+
+	rtw_startbss_cmd(padapter, RTW_CMDF_WAIT_ACK);
+	{
+		int sk_band = RTW_GET_SCAN_BAND_SKIP(padapter);
+
+		if (sk_band)
+			RTW_CLR_SCAN_BAND_SKIP(padapter, sk_band);
+	}
+
+	rtw_indicate_connect(padapter);
+
+	pmlmepriv->cur_network.join_res = _TRUE;/* for check if already set beacon */
+
+	/* update bc/mc sta_info */
+	/* update_bmc_sta(padapter); */
+
+	return ret;
+
+}
+
+void rtw_macaddr_acl_init(_adapter *adapter)
+{
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct wlan_acl_pool *acl = &stapriv->acl_list;
+	_queue *acl_node_q = &acl->acl_node_q;
+	int i;
+	_irqL irqL;
+
+	_enter_critical_bh(&(acl_node_q->lock), &irqL);
+	_rtw_init_listhead(&(acl_node_q->queue));
+	acl->num = 0;
+	acl->mode = RTW_ACL_MODE_DISABLED;
+	for (i = 0; i < NUM_ACL; i++) {
+		_rtw_init_listhead(&acl->aclnode[i].list);
+		acl->aclnode[i].valid = _FALSE;
+	}
+	_exit_critical_bh(&(acl_node_q->lock), &irqL);
+}
+
+void rtw_macaddr_acl_deinit(_adapter *adapter)
+{
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct wlan_acl_pool *acl = &stapriv->acl_list;
+	_queue *acl_node_q = &acl->acl_node_q;
+	_irqL irqL;
+	_list *head, *list;
+	struct rtw_wlan_acl_node *acl_node;
+
+	_enter_critical_bh(&(acl_node_q->lock), &irqL);
+	head = get_list_head(acl_node_q);
+	list = get_next(head);
+	while (rtw_end_of_queue_search(head, list) == _FALSE) {
+		acl_node = LIST_CONTAINOR(list, struct rtw_wlan_acl_node, list);
+		list = get_next(list);
+
+		if (acl_node->valid == _TRUE) {
+			acl_node->valid = _FALSE;
+			rtw_list_delete(&acl_node->list);
+			acl->num--;
+		}
+	}
+	_exit_critical_bh(&(acl_node_q->lock), &irqL);
+
+	rtw_warn_on(acl->num);
+	acl->mode = RTW_ACL_MODE_DISABLED;
+}
+
+void rtw_set_macaddr_acl(_adapter *adapter, int mode)
+{
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct wlan_acl_pool *acl = &stapriv->acl_list;
+
+	RTW_INFO(FUNC_ADPT_FMT" mode=%d\n", FUNC_ADPT_ARG(adapter), mode);
+
+	acl->mode = mode;
+
+	if (mode == RTW_ACL_MODE_DISABLED)
+		rtw_macaddr_acl_deinit(adapter);
+}
+
+int rtw_acl_add_sta(_adapter *adapter, const u8 *addr)
+{
+	_irqL irqL;
+	_list *list, *head;
+	u8 existed = 0;
+	int i = -1, ret = 0;
+	struct rtw_wlan_acl_node *acl_node;
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct wlan_acl_pool *acl = &stapriv->acl_list;
+	_queue *acl_node_q = &acl->acl_node_q;
+
+	_enter_critical_bh(&(acl_node_q->lock), &irqL);
+
+	head = get_list_head(acl_node_q);
+	list = get_next(head);
+
+	/* search for existed entry */
+	while (rtw_end_of_queue_search(head, list) == _FALSE) {
+		acl_node = LIST_CONTAINOR(list, struct rtw_wlan_acl_node, list);
+		list = get_next(list);
+
+		if (_rtw_memcmp(acl_node->addr, addr, ETH_ALEN)) {
+			if (acl_node->valid == _TRUE) {
+				existed = 1;
+				break;
+			}
+		}
+	}
+	if (existed)
+		goto release_lock;
+
+	if (acl->num >= NUM_ACL)
+		goto release_lock;
+
+	/* find empty one and use */
+	for (i = 0; i < NUM_ACL; i++) {
+
+		acl_node = &acl->aclnode[i];
+		if (acl_node->valid == _FALSE) {
+
+			_rtw_init_listhead(&acl_node->list);
+			_rtw_memcpy(acl_node->addr, addr, ETH_ALEN);
+			acl_node->valid = _TRUE;
+
+			rtw_list_insert_tail(&acl_node->list, get_list_head(acl_node_q));
+			acl->num++;
+			break;
+		}
+	}
+
+release_lock:
+	_exit_critical_bh(&(acl_node_q->lock), &irqL);
+
+	if (!existed && (i < 0 || i >= NUM_ACL))
+		ret = -1;
+
+	RTW_INFO(FUNC_ADPT_FMT" "MAC_FMT" %s (acl_num=%d)\n"
+		 , FUNC_ADPT_ARG(adapter), MAC_ARG(addr)
+		, (existed ? "existed" : ((i < 0 || i >= NUM_ACL) ? "no room" : "added"))
+		 , acl->num);
+
+	return ret;
+}
+
+int rtw_acl_remove_sta(_adapter *adapter, const u8 *addr)
+{
+	_irqL irqL;
+	_list *list, *head;
+	int ret = 0;
+	struct rtw_wlan_acl_node *acl_node;
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct wlan_acl_pool *acl = &stapriv->acl_list;
+	_queue	*acl_node_q = &acl->acl_node_q;
+	u8 is_baddr = is_broadcast_mac_addr(addr);
+	u8 match = 0;
+
+	_enter_critical_bh(&(acl_node_q->lock), &irqL);
+
+	head = get_list_head(acl_node_q);
+	list = get_next(head);
+
+	while (rtw_end_of_queue_search(head, list) == _FALSE) {
+		acl_node = LIST_CONTAINOR(list, struct rtw_wlan_acl_node, list);
+		list = get_next(list);
+
+		if (is_baddr || _rtw_memcmp(acl_node->addr, addr, ETH_ALEN)) {
+			if (acl_node->valid == _TRUE) {
+				acl_node->valid = _FALSE;
+				rtw_list_delete(&acl_node->list);
+				acl->num--;
+				match = 1;
+			}
+		}
+	}
+
+	_exit_critical_bh(&(acl_node_q->lock), &irqL);
+
+	RTW_INFO(FUNC_ADPT_FMT" "MAC_FMT" %s (acl_num=%d)\n"
+		 , FUNC_ADPT_ARG(adapter), MAC_ARG(addr)
+		 , is_baddr ? "clear all" : (match ? "match" : "no found")
+		 , acl->num);
+
+	return ret;
+}
+
+u8 rtw_ap_set_pairwise_key(_adapter *padapter, struct sta_info *psta)
+{
+	struct cmd_obj			*ph2c;
+	struct set_stakey_parm	*psetstakey_para;
+	struct cmd_priv			*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	psetstakey_para = (struct set_stakey_parm *)rtw_zmalloc(sizeof(struct set_stakey_parm));
+	if (psetstakey_para == NULL) {
+		rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+
+	psetstakey_para->algorithm = (u8)psta->dot118021XPrivacy;
+
+	_rtw_memcpy(psetstakey_para->addr, psta->hwaddr, ETH_ALEN);
+
+	_rtw_memcpy(psetstakey_para->key, &psta->dot118021x_UncstKey, 16);
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+	return res;
+
+}
+
+static int rtw_ap_set_key(_adapter *padapter, u8 *key, u8 alg, int keyid, u8 set_tx)
+{
+	u8 keylen;
+	struct cmd_obj *pcmd;
+	struct setkey_parm *psetkeyparm;
+	struct cmd_priv	*pcmdpriv = &(padapter->cmdpriv);
+	int res = _SUCCESS;
+
+	/* RTW_INFO("%s\n", __FUNCTION__); */
+
+	pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (pcmd == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	psetkeyparm = (struct setkey_parm *)rtw_zmalloc(sizeof(struct setkey_parm));
+	if (psetkeyparm == NULL) {
+		rtw_mfree((unsigned char *)pcmd, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	_rtw_memset(psetkeyparm, 0, sizeof(struct setkey_parm));
+
+	psetkeyparm->keyid = (u8)keyid;
+	if (is_wep_enc(alg))
+		padapter->securitypriv.key_mask |= BIT(psetkeyparm->keyid);
+
+	psetkeyparm->algorithm = alg;
+
+	psetkeyparm->set_tx = set_tx;
+
+	switch (alg) {
+	case _WEP40_:
+		keylen = 5;
+		break;
+	case _WEP104_:
+		keylen = 13;
+		break;
+	case _TKIP_:
+	case _TKIP_WTMIC_:
+	case _AES_:
+	default:
+		keylen = 16;
+	}
+
+	_rtw_memcpy(&(psetkeyparm->key[0]), key, keylen);
+
+	pcmd->cmdcode = _SetKey_CMD_;
+	pcmd->parmbuf = (u8 *)psetkeyparm;
+	pcmd->cmdsz = (sizeof(struct setkey_parm));
+	pcmd->rsp = NULL;
+	pcmd->rspsz = 0;
+
+	_rtw_init_listhead(&pcmd->list);
+
+	res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+
+exit:
+
+	return res;
+}
+
+int rtw_ap_set_group_key(_adapter *padapter, u8 *key, u8 alg, int keyid)
+{
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	return rtw_ap_set_key(padapter, key, alg, keyid, 1);
+}
+
+int rtw_ap_set_wep_key(_adapter *padapter, u8 *key, u8 keylen, int keyid, u8 set_tx)
+{
+	u8 alg;
+
+	switch (keylen) {
+	case 5:
+		alg = _WEP40_;
+		break;
+	case 13:
+		alg = _WEP104_;
+		break;
+	default:
+		alg = _NO_PRIVACY_;
+	}
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	return rtw_ap_set_key(padapter, key, alg, keyid, set_tx);
+}
+
+static void associated_stainfo_update(_adapter *padapter, struct sta_info *psta, u32 sta_info_type)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	RTW_INFO("%s: "MAC_FMT", updated_type=0x%x\n", __func__, MAC_ARG(psta->hwaddr), sta_info_type);
+
+	if (sta_info_type & STA_INFO_UPDATE_BW) {
+
+		if ((psta->flags & WLAN_STA_HT) && !psta->ht_20mhz_set) {
+			if (pmlmepriv->sw_to_20mhz) {
+				psta->bw_mode = CHANNEL_WIDTH_20;
+				/*psta->htpriv.ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;*/
+				psta->htpriv.sgi_40m = _FALSE;
+			} else {
+				/*TODO: Switch back to 40MHZ?80MHZ*/
+			}
+		}
+	}
+
+	/*
+		if (sta_info_type & STA_INFO_UPDATE_RATE) {
+
+		}
+	*/
+
+	if (sta_info_type & STA_INFO_UPDATE_PROTECTION_MODE)
+		VCS_update(padapter, psta);
+
+	/*
+		if (sta_info_type & STA_INFO_UPDATE_CAP) {
+
+		}
+
+		if (sta_info_type & STA_INFO_UPDATE_HT_CAP) {
+
+		}
+
+		if (sta_info_type & STA_INFO_UPDATE_VHT_CAP) {
+
+		}
+	*/
+
+}
+
+static void update_bcn_ext_capab_ie(_adapter *padapter)
+{
+	sint ie_len = 0;
+	unsigned char	*pbuf;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network);
+	u8 *ie = pnetwork->IEs;
+	u8 null_extcap_data[8] = {0};
+
+	pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_CAP_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+	if (pbuf && ie_len > 0)
+		rtw_remove_bcn_ie(padapter, pnetwork, _EXT_CAP_IE_);
+
+	if ((pmlmepriv->ext_capab_ie_len > 0) &&
+	    (_rtw_memcmp(pmlmepriv->ext_capab_ie_data, null_extcap_data, sizeof(null_extcap_data)) == _FALSE))
+		rtw_add_bcn_ie(padapter, pnetwork, _EXT_CAP_IE_, pmlmepriv->ext_capab_ie_data, pmlmepriv->ext_capab_ie_len);
+
+}
+
+static void update_bcn_fixed_ie(_adapter *padapter)
+{
+	RTW_INFO("%s\n", __FUNCTION__);
+
+}
+
+static void update_bcn_erpinfo_ie(_adapter *padapter)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network);
+	unsigned char *p, *ie = pnetwork->IEs;
+	u32 len = 0;
+
+	RTW_INFO("%s, ERP_enable=%d\n", __FUNCTION__, 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) {
+		PNDIS_802_11_VARIABLE_IEs pIE = (PNDIS_802_11_VARIABLE_IEs)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(_adapter *padapter)
+{
+	RTW_INFO("%s\n", __FUNCTION__);
+
+}
+
+static void update_bcn_htinfo_ie(_adapter *padapter)
+{
+	/*
+	u8 beacon_updated = _FALSE;
+	u32 sta_info_update_type = STA_INFO_UPDATE_NONE;
+	*/
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network);
+	unsigned char *p, *ie = pnetwork->IEs;
+	u32 len = 0;
+
+	if (pmlmepriv->htpriv.ht_option == _FALSE)
+		return;
+
+	if (pmlmeinfo->HT_info_enable != 1)
+		return;
+
+	RTW_INFO("%s current operation mode=0x%X\n",
+		 __FUNCTION__, pmlmepriv->ht_op_mode);
+
+	RTW_INFO("num_sta_40mhz_intolerant(%d), 20mhz_width_req(%d), intolerant_ch_rpt(%d), olbc(%d)\n",
+		pmlmepriv->num_sta_40mhz_intolerant, pmlmepriv->ht_20mhz_width_req, pmlmepriv->ht_intolerant_ch_reported, ATOMIC_READ(&pmlmepriv->olbc));
+
+	/*parsing HT_INFO_IE, currently only update ht_op_mode - pht_info->infos[1] & pht_info->infos[2] for wifi logo test*/
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+	if (p && len > 0) {
+		struct HT_info_element *pht_info = NULL;
+
+		pht_info = (struct HT_info_element *)(p + 2);
+
+		/* for STA Channel Width/Secondary Channel Offset*/
+		if ((pmlmepriv->sw_to_20mhz == 0) && (pmlmeext->cur_channel <= 14)) {
+			if ((pmlmepriv->num_sta_40mhz_intolerant > 0) || (pmlmepriv->ht_20mhz_width_req == _TRUE)
+			    || (pmlmepriv->ht_intolerant_ch_reported == _TRUE) || (ATOMIC_READ(&pmlmepriv->olbc) == _TRUE)) {
+				SET_HT_OP_ELE_2ND_CHL_OFFSET(pht_info, 0);
+				SET_HT_OP_ELE_STA_CHL_WIDTH(pht_info, 0);
+
+				pmlmepriv->sw_to_20mhz = 1;
+				/*
+				sta_info_update_type |= STA_INFO_UPDATE_BW;
+				beacon_updated = _TRUE;
+				*/
+
+				RTW_INFO("%s:switching to 20Mhz\n", __FUNCTION__);
+
+				/*TODO : cur_bwmode/cur_ch_offset switches to 20Mhz*/
+			}
+		} else {
+
+			if ((pmlmepriv->num_sta_40mhz_intolerant == 0) && (pmlmepriv->ht_20mhz_width_req == _FALSE)
+			    && (pmlmepriv->ht_intolerant_ch_reported == _FALSE) && (ATOMIC_READ(&pmlmepriv->olbc) == _FALSE)) {
+
+				if (pmlmeext->cur_bwmode >= CHANNEL_WIDTH_40) {
+
+					SET_HT_OP_ELE_STA_CHL_WIDTH(pht_info, 1);
+
+					SET_HT_OP_ELE_2ND_CHL_OFFSET(pht_info,
+						(pmlmeext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) ?
+						HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE : HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW);
+
+					pmlmepriv->sw_to_20mhz = 0;
+					/*
+					sta_info_update_type |= STA_INFO_UPDATE_BW;
+					beacon_updated = _TRUE;
+					*/
+
+					RTW_INFO("%s:switching back to 40Mhz\n", __FUNCTION__);
+				}
+			}
+		}
+
+		/* to update  ht_op_mode*/
+		*(u16 *)(pht_info->infos + 1) = cpu_to_le16(pmlmepriv->ht_op_mode);
+
+	}
+
+	/*associated_clients_update(padapter, beacon_updated, sta_info_update_type);*/
+
+}
+
+static void update_bcn_rsn_ie(_adapter *padapter)
+{
+	RTW_INFO("%s\n", __FUNCTION__);
+
+}
+
+static void update_bcn_wpa_ie(_adapter *padapter)
+{
+	RTW_INFO("%s\n", __FUNCTION__);
+
+}
+
+static void update_bcn_wmm_ie(_adapter *padapter)
+{
+	RTW_INFO("%s\n", __FUNCTION__);
+
+}
+
+static void update_bcn_wps_ie(_adapter *padapter)
+{
+	u8 *pwps_ie = NULL, *pwps_ie_src, *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);
+	WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network);
+	unsigned char *ie = pnetwork->IEs;
+	u32 ielen = pnetwork->IELength;
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	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;
+
+	pwps_ie_src = pmlmepriv->wps_beacon_ie;
+	if (pwps_ie_src == NULL)
+		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)
+			_rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+	}
+
+	wps_ielen = (uint)pwps_ie_src[1];/* to get ie data len */
+	if ((wps_offset + wps_ielen + 2 + remainder_ielen) <= MAX_IE_SZ) {
+		_rtw_memcpy(pwps_ie, pwps_ie_src, wps_ielen + 2);
+		pwps_ie += (wps_ielen + 2);
+
+		if (pbackup_remainder_ie)
+			_rtw_memcpy(pwps_ie, pbackup_remainder_ie, remainder_ielen);
+
+		/* update IELength */
+		pnetwork->IELength = wps_offset + (wps_ielen + 2) + remainder_ielen;
+	}
+
+	if (pbackup_remainder_ie)
+		rtw_mfree(pbackup_remainder_ie, remainder_ielen);
+
+	/* deal with the case without set_tx_beacon_cmd() in update_beacon() */
+	if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) {
+		u8 sr = 0;
+		rtw_get_wps_attr_content(pwps_ie_src,  wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL);
+
+		if (sr) {
+			set_fwstate(pmlmepriv, WIFI_UNDER_WPS);
+			RTW_INFO("%s, set WIFI_UNDER_WPS\n", __func__);
+		} else {
+			clr_fwstate(pmlmepriv, WIFI_UNDER_WPS);
+			RTW_INFO("%s, clr WIFI_UNDER_WPS\n", __func__);
+		}
+	}
+}
+
+static void update_bcn_p2p_ie(_adapter *padapter)
+{
+
+}
+
+static void update_bcn_vendor_spec_ie(_adapter *padapter, u8 *oui)
+{
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	if (_rtw_memcmp(RTW_WPA_OUI, oui, 4))
+		update_bcn_wpa_ie(padapter);
+	else if (_rtw_memcmp(WMM_OUI, oui, 4))
+		update_bcn_wmm_ie(padapter);
+	else if (_rtw_memcmp(WPS_OUI, oui, 4))
+		update_bcn_wps_ie(padapter);
+	else if (_rtw_memcmp(P2P_OUI, oui, 4))
+		update_bcn_p2p_ie(padapter);
+	else
+		RTW_INFO("unknown OUI type!\n");
+
+}
+
+void _update_beacon(_adapter *padapter, u8 ie_id, u8 *oui, u8 tx, const char *tag)
+{
+	_irqL irqL;
+	struct mlme_priv *pmlmepriv;
+	struct mlme_ext_priv	*pmlmeext;
+	/* struct mlme_ext_info	*pmlmeinfo; */
+
+	/* RTW_INFO("%s\n", __FUNCTION__); */
+
+	if (!padapter)
+		return;
+
+	pmlmepriv = &(padapter->mlmepriv);
+	pmlmeext = &(padapter->mlmeextpriv);
+	/* pmlmeinfo = &(pmlmeext->mlmext_info); */
+
+	if (_FALSE == pmlmeext->bstart_bss)
+		return;
+
+	_enter_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
+
+	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 _EXT_CAP_IE_:
+
+		update_bcn_ext_capab_ie(padapter);
+
+		break;
+
+	case _VENDOR_SPECIFIC_IE_:
+
+		update_bcn_vendor_spec_ie(padapter, oui);
+
+		break;
+
+	default:
+		break;
+	}
+
+	pmlmepriv->update_bcn = _TRUE;
+
+	_exit_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
+}
+
+
+void rtw_process_public_act_bsscoex(_adapter *padapter, u8 *pframe, uint frame_len)
+{
+	struct sta_info *psta;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 beacon_updated = _FALSE;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
+	uint frame_body_len = frame_len - sizeof(struct rtw_ieee80211_hdr_3addr);
+	u8 category, action;
+
+	psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe));
+	if (psta == NULL)
+		return;
+
+	category = frame_body[0];
+	action = frame_body[1];
+
+	if (frame_body_len > 0) {
+		if ((frame_body[2] == EID_BSSCoexistence) && (frame_body[3] > 0)) {
+			u8 ie_data = frame_body[4];
+
+			if (ie_data & RTW_WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
+				if (psta->ht_40mhz_intolerant == 0) {
+					psta->ht_40mhz_intolerant = 1;
+					pmlmepriv->num_sta_40mhz_intolerant++;
+					beacon_updated = _TRUE;
+				}
+			} else if (ie_data & RTW_WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ)	{
+				if (pmlmepriv->ht_20mhz_width_req == _FALSE) {
+					pmlmepriv->ht_20mhz_width_req = _TRUE;
+					beacon_updated = _TRUE;
+				}
+			} else
+				beacon_updated = _FALSE;
+		}
+	}
+
+	if (frame_body_len > 8) {
+		/* if EID_BSSIntolerantChlReport ie exists */
+		if ((frame_body[5] == EID_BSSIntolerantChlReport) && (frame_body[6] > 0)) {
+			/*todo:*/
+			if (pmlmepriv->ht_intolerant_ch_reported == _FALSE) {
+				pmlmepriv->ht_intolerant_ch_reported = _TRUE;
+				beacon_updated = _TRUE;
+			}
+		}
+	}
+
+	if (beacon_updated) {
+
+		update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _TRUE);
+
+		associated_stainfo_update(padapter, psta, STA_INFO_UPDATE_BW);
+	}
+
+}
+
+void rtw_process_ht_action_smps(_adapter *padapter, u8 *ta, u8 ctrl_field)
+{
+	u8 e_field, m_field;
+	struct sta_info *psta;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	psta = rtw_get_stainfo(pstapriv, ta);
+	if (psta == NULL)
+		return;
+
+	e_field = (ctrl_field & BIT(0)) ? 1 : 0;
+	m_field = (ctrl_field & BIT(1)) ? 1 : 0;
+
+	if (e_field) {
+
+		/* enable */
+		/* 0:static SMPS, 1:dynamic SMPS, 3:SMPS disabled, 2:reserved*/
+
+		if (m_field) /*mode*/
+			psta->htpriv.smps_cap = 1;
+		else
+			psta->htpriv.smps_cap = 0;
+	} else {
+		/*disable*/
+		psta->htpriv.smps_cap = 3;
+	}
+
+	rtw_dm_ra_mask_wk_cmd(padapter, (u8 *)psta);
+
+}
+
+/*
+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)
+*/
+int rtw_ht_operation_update(_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 == _FALSE)
+		return 0;
+
+	/*if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed)
+		return 0;*/
+
+	RTW_INFO("%s current operation mode=0x%X\n",
+		 __FUNCTION__, 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 || ATOMIC_READ(&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 && !ATOMIC_READ(&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 ((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 (ATOMIC_READ(&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++;
+	}
+
+	RTW_INFO("%s new operation mode=0x%X changes=%d\n",
+		 __FUNCTION__, pmlmepriv->ht_op_mode, op_mode_changes);
+
+	return op_mode_changes;
+
+}
+
+
+void associated_clients_update(_adapter *padapter, u8 updated, u32 sta_info_type)
+{
+	/* update associcated stations cap. */
+	if (updated == _TRUE) {
+		_irqL irqL;
+		_list	*phead, *plist;
+		struct sta_info *psta = NULL;
+		struct sta_priv *pstapriv = &padapter->stapriv;
+
+		_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+		phead = &pstapriv->asoc_list;
+		plist = get_next(phead);
+
+		/* check asoc_queue */
+		while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+			psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+
+			plist = get_next(plist);
+
+			associated_stainfo_update(padapter, psta, sta_info_type);
+		}
+
+		_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	}
+
+}
+
+/* called > TSR LEVEL for USB or SDIO Interface*/
+void bss_cap_update_on_sta_join(_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);
+
+		RTW_INFO("HT: STA " MAC_FMT " HT Capabilities "
+			 "Info: 0x%04x\n", MAC_ARG(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++;
+			}
+			RTW_INFO("%s STA " MAC_FMT " - no "
+				 "greenfield, num of non-gf stations %d\n",
+				 __FUNCTION__, MAC_ARG(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++;
+			}
+			RTW_INFO("%s STA " MAC_FMT " - 20 MHz HT, "
+				 "num of 20MHz HT STAs %d\n",
+				 __FUNCTION__, MAC_ARG(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 == _TRUE) {
+			RTW_INFO("%s STA " MAC_FMT
+				 " - no HT, num of non-HT stations %d\n",
+				 __FUNCTION__, MAC_ARG(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);
+		/*beacon_updated = _TRUE;*/
+	}
+
+
+	/* update associcated stations cap. */
+	associated_clients_update(padapter,  beacon_updated, STA_INFO_UPDATE_ALL);
+
+	RTW_INFO("%s, updated=%d\n", __func__, beacon_updated);
+
+}
+
+u8 bss_cap_update_on_sta_leave(_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);
+	}
+
+	RTW_INFO("%s, updated=%d\n", __func__, beacon_updated);
+
+	return beacon_updated;
+}
+
+u8 ap_free_sta(_adapter *padapter, struct sta_info *psta, bool active, u16 reason, bool enqueue)
+{
+	_irqL irqL;
+	u8 beacon_updated = _FALSE;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	if (!psta)
+		return beacon_updated;
+
+	if (active == _TRUE) {
+		/* tear down Rx AMPDU */
+		send_delba(padapter, 0, psta->hwaddr);/* recipient */
+
+		/* tear down TX AMPDU */
+		send_delba(padapter, 1, psta->hwaddr);/*  */ /* originator */
+
+
+		issue_deauth(padapter, psta->hwaddr, reason);
+	}
+
+
+	psta->htpriv.agg_enable_bitmap = 0x0;/* reset */
+	psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */
+
+	/* clear cam entry / key */
+	rtw_clearstakey_cmd(padapter, psta, enqueue);
+
+	_enter_critical_bh(&psta->lock, &irqL);
+	psta->state &= ~_FW_LINKED;
+	_exit_critical_bh(&psta->lock, &irqL);
+
+	{
+		rtw_indicate_sta_disassoc_event(padapter, psta);
+	}
+
+	report_del_sta_event(padapter, psta->hwaddr, reason, enqueue, _FALSE);
+
+	beacon_updated = bss_cap_update_on_sta_leave(padapter, psta);
+
+	/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);					 */
+	rtw_free_stainfo(padapter, psta);
+	/* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
+
+	return beacon_updated;
+
+}
+
+int rtw_sta_flush(_adapter *padapter, bool enqueue)
+{
+	_irqL irqL;
+	_list	*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};
+	u8 flush_num = 0;
+	char flush_list[NUM_STA];
+	int i;
+
+	if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)
+		return ret;
+
+	RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
+
+	/* pick sta from sta asoc_queue */
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+		int stainfo_offset;
+
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		plist = get_next(plist);
+
+		rtw_list_delete(&psta->asoc_list);
+		pstapriv->asoc_list_cnt--;
+
+		stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
+		if (stainfo_offset_valid(stainfo_offset))
+			flush_list[flush_num++] = stainfo_offset;
+		else
+			rtw_warn_on(1);
+	}
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	/* call ap_free_sta() for each sta picked */
+	for (i = 0; i < flush_num; i++) {
+		psta = rtw_get_stainfo_by_offset(pstapriv, flush_list[i]);
+		ap_free_sta(padapter, psta, _TRUE, WLAN_REASON_DEAUTH_LEAVING, enqueue);
+	}
+
+	issue_deauth(padapter, bc_addr, WLAN_REASON_DEAUTH_LEAVING);
+
+	associated_clients_update(padapter, _TRUE, STA_INFO_UPDATE_ALL);
+
+	return ret;
+}
+
+/* called > TSR LEVEL for USB or SDIO Interface*/
+void sta_info_update(_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;
+
+		psta->htpriv.smps_cap = (psta->htpriv.ht_cap.cap_info & IEEE80211_HT_CAP_SM_PS) >> 2;
+	} else
+		psta->htpriv.ht_option = _FALSE;
+
+	if (pmlmepriv->htpriv.ht_option == _FALSE)
+		psta->htpriv.ht_option = _FALSE;
+
+	/* update 802.11AC vht cap. */
+	if (WLAN_STA_VHT & flags)
+		psta->vhtpriv.vht_option = _TRUE;
+	else
+		psta->vhtpriv.vht_option = _FALSE;
+
+	if (pmlmepriv->vhtpriv.vht_option == _FALSE)
+		psta->vhtpriv.vht_option = _FALSE;
+
+	update_sta_info_apmode(padapter, psta);
+}
+
+/* called >= TSR LEVEL for USB or SDIO Interface*/
+void ap_sta_info_defer_update(_adapter *padapter, struct sta_info *psta)
+{
+	if (psta->state & _FW_LINKED)
+		rtw_hal_update_ra_mask(psta, psta->rssi_level, _TRUE); /* DM_RATR_STA_INIT */
+}
+/* restore hw setting from sw data structures */
+void rtw_ap_restore_network(_adapter *padapter)
+{
+	struct mlme_priv *mlmepriv = &padapter->mlmepriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct sta_info *psta;
+	struct security_priv *psecuritypriv = &(padapter->securitypriv);
+	_irqL irqL;
+	_list	*phead, *plist;
+	u8 chk_alive_num = 0;
+	char chk_alive_list[NUM_STA];
+	int i;
+
+	rtw_setopmode_cmd(padapter, Ndis802_11APMode, _FALSE);
+
+	set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+	rtw_startbss_cmd(padapter, RTW_CMDF_DIRECTLY);
+
+	if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) ||
+	    (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) {
+		/* restore group key, WEP keys is restored in ips_leave() */
+		rtw_set_key(padapter, psecuritypriv, psecuritypriv->dot118021XGrpKeyid, 0, _FALSE);
+	}
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+		int stainfo_offset;
+
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		plist = get_next(plist);
+
+		stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
+		if (stainfo_offset_valid(stainfo_offset))
+			chk_alive_list[chk_alive_num++] = stainfo_offset;
+	}
+
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	for (i = 0; i < chk_alive_num; i++) {
+		psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
+
+		if (psta == NULL)
+			RTW_INFO(FUNC_ADPT_FMT" sta_info is null\n", FUNC_ADPT_ARG(padapter));
+		else if (psta->state & _FW_LINKED) {
+			rtw_sta_media_status_rpt(padapter, psta, 1);
+			Update_RA_Entry(padapter, psta);
+			/* pairwise key */
+			/* per sta pairwise key and settings */
+			if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) ||
+			    (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_))
+				rtw_setstakey_cmd(padapter, psta, UNICAST_KEY, _FALSE);
+		}
+	}
+
+}
+
+void start_ap_mode(_adapter *padapter)
+{
+	int i;
+	struct sta_info *psta = NULL;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+	pmlmepriv->update_bcn = _FALSE;
+
+	/*init_mlme_ap_info(padapter);*/
+
+	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;
+	pmlmeinfo->HT_info_enable = 0;
+	pmlmeinfo->HT_caps_enable = 0;
+	pmlmeinfo->HT_enable = 0;
+
+	pmlmepriv->num_sta_ht_20mhz = 0;
+	pmlmepriv->num_sta_40mhz_intolerant = 0;
+	ATOMIC_SET(&pmlmepriv->olbc, _FALSE);
+	ATOMIC_SET(&pmlmepriv->olbc_ht, _FALSE);
+
+	pmlmepriv->ht_20mhz_width_req = _FALSE;
+	pmlmepriv->ht_intolerant_ch_reported = _FALSE;
+	pmlmepriv->ht_op_mode = 0;
+	pmlmepriv->sw_to_20mhz = 0;
+
+	_rtw_memset(pmlmepriv->ext_capab_ie_data, 0, sizeof(pmlmepriv->ext_capab_ie_data));
+	pmlmepriv->ext_capab_ie_len = 0;
+
+
+	for (i = 0 ;  i < NUM_STA ; i++)
+		pstapriv->sta_aid[i] = NULL;
+
+	rtw_macaddr_acl_init(padapter);
+
+	psta = rtw_get_bcmc_stainfo(padapter);
+	/*_enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);*/
+	if (psta)
+		rtw_free_stainfo(padapter, psta);
+	/*_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);*/
+
+	rtw_init_bcmc_stainfo(padapter);
+
+	if (rtw_mi_get_ap_num(padapter))
+		RTW_SET_SCAN_BAND_SKIP(padapter, BAND_5G);
+
+}
+
+void stop_ap_mode(_adapter *padapter)
+{
+	_irqL irqL;
+	struct sta_info *psta = NULL;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct dvobj_priv *pdvobj = padapter->dvobj;
+
+	RTW_INFO("%s -"ADPT_FMT"\n", __func__, ADPT_ARG(padapter));
+
+	pmlmepriv->update_bcn = _FALSE;
+	/*pmlmeext->bstart_bss = _FALSE;*/
+	padapter->netif_up = _FALSE;
+	/* _rtw_spinlock_free(&pmlmepriv->bcn_update_lock); */
+
+	/* reset and init security priv , this can refine with rtw_reset_securitypriv */
+	_rtw_memset((unsigned char *)&padapter->securitypriv, 0, sizeof(struct security_priv));
+	padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+	padapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
+
+
+	/* free scan queue */
+	rtw_free_network_queue(padapter, _TRUE);
+
+	rtw_macaddr_acl_deinit(padapter);
+
+	rtw_sta_flush(padapter, _TRUE);
+
+	/* free_assoc_sta_resources	 */
+	rtw_free_all_stainfo(padapter);
+
+	psta = rtw_get_bcmc_stainfo(padapter);
+	/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);		 */
+	rtw_free_stainfo(padapter, psta);
+	/*_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);*/
+
+	rtw_free_mlme_priv_ie_data(pmlmepriv);
+
+
+	pmlmeext->bstart_bss = _FALSE;
+
+	rtw_btcoex_MediaStatusNotify(padapter, 0); /* disconnect */
+
+}
+
+
+void rtw_ap_update_bss_chbw(_adapter *adapter, WLAN_BSSID_EX *bss, u8 ch, u8 bw, u8 offset)
+{
+#define UPDATE_VHT_CAP 1
+#define UPDATE_HT_CAP 1
+
+	{
+		struct vht_priv	*vhtpriv = &adapter->mlmepriv.vhtpriv;
+		u8 *vht_cap_ie, *vht_op_ie;
+		int vht_cap_ielen, vht_op_ielen;
+		u8	center_freq;
+
+		vht_cap_ie = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), EID_VHTCapability, &vht_cap_ielen, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)));
+		vht_op_ie = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), EID_VHTOperation, &vht_op_ielen, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)));
+		center_freq = rtw_get_center_ch(ch, bw, offset);
+
+		/* update vht cap ie */
+		if (vht_cap_ie && vht_cap_ielen) {
+			/* if ((bw == CHANNEL_WIDTH_160 || bw == CHANNEL_WIDTH_80_80) && pvhtpriv->sgi_160m)
+				SET_VHT_CAPABILITY_ELE_SHORT_GI160M(pvht_cap_ie + 2, 1);
+			else */
+				SET_VHT_CAPABILITY_ELE_SHORT_GI160M(vht_cap_ie + 2, 0);
+
+			if (bw >= CHANNEL_WIDTH_80 && vhtpriv->sgi_80m)
+				SET_VHT_CAPABILITY_ELE_SHORT_GI80M(vht_cap_ie + 2, 1);
+			else
+				SET_VHT_CAPABILITY_ELE_SHORT_GI80M(vht_cap_ie + 2, 0);
+		}
+
+		/* update vht op ie */
+		if (vht_op_ie && vht_op_ielen) {
+			if (bw < CHANNEL_WIDTH_80) {
+				SET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2, 0);
+				SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(vht_op_ie + 2, 0);
+				SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(vht_op_ie + 2, 0);
+			} else if (bw == CHANNEL_WIDTH_80) {
+				SET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2, 1);
+				SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(vht_op_ie + 2, center_freq);
+				SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(vht_op_ie + 2, 0);
+			} else {
+				RTW_ERR(FUNC_ADPT_FMT" unsupported BW:%u\n", FUNC_ADPT_ARG(adapter), bw);
+				rtw_warn_on(1);
+			}
+		}
+	}
+	{
+		struct ht_priv	*htpriv = &adapter->mlmepriv.htpriv;
+		u8 *ht_cap_ie, *ht_op_ie;
+		int ht_cap_ielen, ht_op_ielen;
+
+		ht_cap_ie = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), EID_HTCapability, &ht_cap_ielen, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)));
+		ht_op_ie = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), EID_HTInfo, &ht_op_ielen, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)));
+
+		/* update ht cap ie */
+		if (ht_cap_ie && ht_cap_ielen) {
+			if (bw >= CHANNEL_WIDTH_40)
+				SET_HT_CAP_ELE_CHL_WIDTH(ht_cap_ie + 2, 1);
+			else
+				SET_HT_CAP_ELE_CHL_WIDTH(ht_cap_ie + 2, 0);
+
+			if (bw >= CHANNEL_WIDTH_40 && htpriv->sgi_40m)
+				SET_HT_CAP_ELE_SHORT_GI40M(ht_cap_ie + 2, 1);
+			else
+				SET_HT_CAP_ELE_SHORT_GI40M(ht_cap_ie + 2, 0);
+
+			if (htpriv->sgi_20m)
+				SET_HT_CAP_ELE_SHORT_GI20M(ht_cap_ie + 2, 1);
+			else
+				SET_HT_CAP_ELE_SHORT_GI20M(ht_cap_ie + 2, 0);
+		}
+
+		/* update ht op ie */
+		if (ht_op_ie && ht_op_ielen) {
+			SET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2, ch);
+			switch (offset) {
+			case HAL_PRIME_CHNL_OFFSET_LOWER:
+				SET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2, SCA);
+				break;
+			case HAL_PRIME_CHNL_OFFSET_UPPER:
+				SET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2, SCB);
+				break;
+			case HAL_PRIME_CHNL_OFFSET_DONT_CARE:
+			default:
+				SET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2, SCN);
+				break;
+			}
+
+			if (bw >= CHANNEL_WIDTH_40)
+				SET_HT_OP_ELE_STA_CHL_WIDTH(ht_op_ie + 2, 1);
+			else
+				SET_HT_OP_ELE_STA_CHL_WIDTH(ht_op_ie + 2, 0);
+		}
+	}
+
+	{
+		u8 *p;
+		int ie_len;
+		u8 old_ch = bss->Configuration.DSConfig;
+		bool change_band = _FALSE;
+
+		if ((ch <= 14 && old_ch >= 36) || (ch >= 36 && old_ch <= 14))
+			change_band = _TRUE;
+
+		/* update channel in IE */
+		p = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), _DSSET_IE_, &ie_len, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)));
+		if (p && ie_len > 0)
+			*(p + 2) = ch;
+
+		bss->Configuration.DSConfig = ch;
+
+		/* band is changed, update ERP, support rate, ext support rate IE */
+		if (change_band == _TRUE)
+			change_band_update_ie(adapter, bss, ch);
+	}
+
+}
+
+bool rtw_ap_chbw_decision(_adapter *adapter, s16 req_ch, s8 req_bw, s8 req_offset
+			  , u8 *ch, u8 *bw, u8 *offset, u8 *chbw_allow)
+{
+	u8 cur_ie_ch, cur_ie_bw, cur_ie_offset;
+	u8 dec_ch, dec_bw, dec_offset;
+	u8 u_ch = 0, u_offset, u_bw;
+	bool changed = _FALSE;
+	struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv);
+	WLAN_BSSID_EX *network = &(adapter->mlmepriv.cur_network.network);
+	struct mi_state mstate;
+	bool set_u_ch = _FALSE, set_dec_ch = _FALSE;
+
+	rtw_ies_get_chbw(network->IEs + sizeof(NDIS_802_11_FIXED_IEs)
+			 , network->IELength - sizeof(NDIS_802_11_FIXED_IEs)
+			 , &cur_ie_ch, &cur_ie_bw, &cur_ie_offset);
+
+	/* use chbw of cur_ie updated with specifying req as temporary decision */
+	dec_ch = (req_ch <= 0) ? cur_ie_ch : req_ch;
+	dec_bw = (req_bw < 0) ? cur_ie_bw : req_bw;
+	dec_offset = (req_offset < 0) ? cur_ie_offset : req_offset;
+
+	rtw_mi_status_no_self(adapter, &mstate);
+	RTW_INFO(FUNC_ADPT_FMT" ld_sta_num:%u, lg_sta_num%u, ap_num:%u\n"
+		, FUNC_ADPT_ARG(adapter), MSTATE_STA_LD_NUM(&mstate), MSTATE_STA_LG_NUM(&mstate), MSTATE_AP_NUM(&mstate));
+
+	if (MSTATE_STA_LD_NUM(&mstate) || MSTATE_AP_NUM(&mstate)) {
+		/* has linked STA or AP mode, follow */
+
+		rtw_warn_on(!rtw_mi_get_ch_setting_union_no_self(adapter, &u_ch, &u_bw, &u_offset));
+
+		RTW_INFO(FUNC_ADPT_FMT" union no self: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset);
+		RTW_INFO(FUNC_ADPT_FMT" req: %d,%d,%d\n", FUNC_ADPT_ARG(adapter), req_ch, req_bw, req_offset);
+
+		rtw_adjust_chbw(adapter, u_ch, &dec_bw, &dec_offset);
+		rtw_sync_chbw(&dec_ch, &dec_bw, &dec_offset
+			      , &u_ch, &u_bw, &u_offset);
+
+		rtw_ap_update_bss_chbw(adapter, &(adapter->mlmepriv.cur_network.network)
+				       , dec_ch, dec_bw, dec_offset);
+
+		set_u_ch = _TRUE;
+	} else if (MSTATE_STA_LG_NUM(&mstate)) {
+		/* has linking STA */
+
+		rtw_warn_on(!rtw_mi_get_ch_setting_union_no_self(adapter, &u_ch, &u_bw, &u_offset));
+
+		RTW_INFO(FUNC_ADPT_FMT" union no self: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset);
+		RTW_INFO(FUNC_ADPT_FMT" req: %d,%d,%d\n", FUNC_ADPT_ARG(adapter), req_ch, req_bw, req_offset);
+
+		rtw_adjust_chbw(adapter, dec_ch, &dec_bw, &dec_offset);
+
+		if (rtw_is_chbw_grouped(u_ch, u_bw, u_offset, dec_ch, dec_bw, dec_offset)) {
+
+			rtw_sync_chbw(&dec_ch, &dec_bw, &dec_offset
+				      , &u_ch, &u_bw, &u_offset);
+
+			rtw_ap_update_bss_chbw(adapter, &(adapter->mlmepriv.cur_network.network)
+					       , dec_ch, dec_bw, dec_offset);
+
+			set_u_ch = _TRUE;
+
+			/* channel bw offset can be allowed, not need MCC */
+			*chbw_allow = _TRUE;
+		} else {
+			/* set this for possible ch change when join down*/
+			set_fwstate(&adapter->mlmepriv, WIFI_OP_CH_SWITCHING);
+		}
+	} else {
+		/* single AP mode */
+
+		RTW_INFO(FUNC_ADPT_FMT" req: %d,%d,%d\n", FUNC_ADPT_ARG(adapter), req_ch, req_bw, req_offset);
+
+		/* check temporary decision first */
+		rtw_adjust_chbw(adapter, dec_ch, &dec_bw, &dec_offset);
+		if (!rtw_get_offset_by_chbw(dec_ch, dec_bw, &dec_offset)) {
+			if (req_ch == -1 || req_bw == -1)
+				goto choose_chbw;
+			RTW_WARN(FUNC_ADPT_FMT" req: %u,%u has no valid offset\n", FUNC_ADPT_ARG(adapter), dec_ch, dec_bw);
+			*chbw_allow = _FALSE;
+			goto exit;
+		}
+
+		if (!rtw_chset_is_chbw_valid(mlmeext->channel_set, dec_ch, dec_bw, dec_offset)) {
+			if (req_ch == -1 || req_bw == -1)
+				goto choose_chbw;
+			RTW_WARN(FUNC_ADPT_FMT" req: %u,%u,%u doesn't fit in chplan\n", FUNC_ADPT_ARG(adapter), dec_ch, dec_bw, dec_offset);
+			*chbw_allow = _FALSE;
+			goto exit;
+		}
+
+		if (rtw_odm_dfs_domain_unknown(adapter) && rtw_is_dfs_chbw(dec_ch, dec_bw, dec_offset)) {
+			if (req_ch >= 0)
+				RTW_WARN(FUNC_ADPT_FMT" DFS channel %u,%u,%u can't be used\n", FUNC_ADPT_ARG(adapter), dec_ch, dec_bw, dec_offset);
+			if (req_ch > 0) {
+				/* specific channel and not from IE => don't change channel setting */
+				*chbw_allow = _FALSE;
+				goto exit;
+			}
+			goto choose_chbw;
+		}
+
+		if (rtw_chset_is_ch_non_ocp(mlmeext->channel_set, dec_ch, dec_bw, dec_offset) == _FALSE)
+			goto update_bss_chbw;
+
+choose_chbw:
+		if (req_bw < 0)
+			req_bw = cur_ie_bw;
+
+		if (rtw_choose_shortest_waiting_ch(adapter, req_bw, &dec_ch, &dec_bw, &dec_offset, RTW_CHF_DFS) == _FALSE) {
+			RTW_WARN(FUNC_ADPT_FMT" no available channel\n", FUNC_ADPT_ARG(adapter));
+			*chbw_allow = _FALSE;
+			goto exit;
+		}
+
+update_bss_chbw:
+		rtw_ap_update_bss_chbw(adapter, &(adapter->mlmepriv.cur_network.network)
+				       , dec_ch, dec_bw, dec_offset);
+
+		/* channel bw offset can be allowed for single AP, not need MCC */
+		*chbw_allow = _TRUE;
+		set_dec_ch = _TRUE;
+	}
+
+	if (rtw_mi_check_fwstate(adapter, _FW_UNDER_SURVEY)) {
+		/* scanning, leave ch setting to scan state machine */
+		set_u_ch = set_dec_ch = _FALSE;
+	}
+
+	if (mlmeext->cur_channel != dec_ch
+	    || mlmeext->cur_bwmode != dec_bw
+	    || mlmeext->cur_ch_offset != dec_offset)
+		changed = _TRUE;
+
+	if (changed == _TRUE && rtw_linked_check(adapter) == _TRUE)
+			rtw_sta_flush(adapter, _FALSE);
+
+	mlmeext->cur_channel = dec_ch;
+	mlmeext->cur_bwmode = dec_bw;
+	mlmeext->cur_ch_offset = dec_offset;
+
+	if (u_ch != 0)
+		RTW_INFO(FUNC_ADPT_FMT" union: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset);
+
+	RTW_INFO(FUNC_ADPT_FMT" dec: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), dec_ch, dec_bw, dec_offset);
+
+	if (set_u_ch == _TRUE) {
+		*ch = u_ch;
+		*bw = u_bw;
+		*offset = u_offset;
+	} else if (set_dec_ch == _TRUE) {
+		*ch = dec_ch;
+		*bw = dec_bw;
+		*offset = dec_offset;
+	}
+exit:
+	return changed;
+}
+
+/*#define DBG_SWTIMER_BASED_TXBCN*/
+
+
diff --git a/drivers/staging/rtl8821ce/core/rtw_br_ext.c b/drivers/staging/rtl8821ce/core/rtw_br_ext.c
new file mode 100644
index 000000000000..7554391408f6
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/rtw_br_ext.c
@@ -0,0 +1,1286 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * 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 <linux/if_arp.h>
+#include <net/ip.h>
+#include <net/ipx.h>
+#include <linux/atalk.h>
+#include <linux/udp.h>
+#include <linux/if_pppox.h>
+
+#include <drv_types.h>
+
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+#include <net/ndisc.h>
+#include <net/ip6_checksum.h>
+
+#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 0;
+}
+
+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(_adapter *priv)
+{
+	unsigned long timeout;
+
+	timeout = jiffies - NAT25_AGEING_TIME * HZ;
+
+	return timeout;
+}
+
+static __inline__ int  __nat25_has_expired(_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) {
+				RTW_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) {
+				RTW_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) {
+				RTW_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) {
+				RTW_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) {
+				RTW_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(_adapter *priv,
+		struct nat25_network_db_entry *ent, int hash)
+{
+	/* Caller must _enter_critical_bh already! */
+	/* _irqL irqL; */
+	/* _enter_critical_bh(&priv->br_ext_lock, &irqL); */
+
+	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];
+
+	/* _exit_critical_bh(&priv->br_ext_lock, &irqL); */
+}
+
+static __inline__ void __network_hash_unlink(struct nat25_network_db_entry *ent)
+{
+	/* Caller must _enter_critical_bh already! */
+	/* _irqL irqL; */
+	/* _enter_critical_bh(&priv->br_ext_lock, &irqL); */
+
+	*(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;
+
+	/* _exit_critical_bh(&priv->br_ext_lock, &irqL); */
+}
+
+static int __nat25_db_network_lookup_and_replace(_adapter *priv,
+		struct sk_buff *skb, unsigned char *networkAddr)
+{
+	struct nat25_network_db_entry *db;
+	_irqL irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+	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);
+
+				RTW_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]);
+			}
+			_exit_critical_bh(&priv->br_ext_lock, &irqL);
+			return 1;
+		}
+
+		db = db->next_hash;
+	}
+
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+	return 0;
+}
+
+static void __nat25_db_network_insert(_adapter *priv,
+		      unsigned char *macAddr, unsigned char *networkAddr)
+{
+	struct nat25_network_db_entry *db;
+	int hash;
+	_irqL irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+	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;
+			_exit_critical_bh(&priv->br_ext_lock, &irqL);
+			return;
+		}
+
+		db = db->next_hash;
+	}
+
+	db = (struct nat25_network_db_entry *) rtw_malloc(sizeof(*db));
+	if (db == NULL) {
+		_exit_critical_bh(&priv->br_ext_lock, &irqL);
+		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);
+
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+static void __nat25_db_print(_adapter *priv)
+{
+	_irqL irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+/*
+ *	NAT2.5 interface
+ */
+
+void nat25_db_cleanup(_adapter *priv)
+{
+	int i;
+	_irqL irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+	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);
+			rtw_mfree((u8 *) f, sizeof(struct nat25_network_db_entry));
+
+			f = g;
+		}
+	}
+
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+void nat25_db_expire(_adapter *priv)
+{
+	int i;
+	_irqL irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+	/* if(!priv->ethBrExtInfo.nat25_disable) */
+	{
+		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);
+						rtw_mfree((u8 *) f, sizeof(struct nat25_network_db_entry));
+					}
+				}
+
+				f = g;
+			}
+		}
+	}
+
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+
+int nat25_db_handle(_adapter *priv, struct sk_buff *skb, int method)
+{
+	unsigned short protocol;
+	unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
+
+	if (skb == NULL)
+		return -1;
+
+	if ((method <= NAT25_MIN) || (method >= NAT25_MAX))
+		return -1;
+
+	protocol = *((unsigned short *)(skb->data + 2 * ETH_ALEN));
+
+	/*---------------------------------------------------*/
+	/*                 Handle IP frame                  */
+	/*---------------------------------------------------*/
+	if (protocol == __constant_htons(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 muticast 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;
+			RTW_INFO("NAT25: Insert IP, SA=%08x, DA=%08x\n", iph->saddr, iph->daddr);
+			__nat25_generate_ipv4_network_addr(networkAddr, &iph->saddr);
+			/* 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: {
+			RTW_INFO("NAT25: Lookup IP, SA=%08x, DA=%08x\n", iph->saddr, iph->daddr);
+			{
+				__nat25_generate_ipv4_network_addr(networkAddr, &iph->daddr);
+
+				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 */
+						RTW_INFO("NAT25: Set DA as boardcast\n");
+						memset(skb->data, 0xff, ETH_ALEN);
+					} else {
+						/* forward unknow IP packet to upper TCP/IP */
+						RTW_INFO("NAT25: Replace DA with BR's MAC\n");
+						if ((*(u32 *)priv->br_mac) == 0 && (*(u16 *)(priv->br_mac + 4)) == 0) {
+							void netdev_br_init(struct net_device *netdev);
+							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;
+		}
+	}
+
+	/*---------------------------------------------------*/
+	/*                 Handle ARP frame                 */
+	/*---------------------------------------------------*/
+	else if (protocol == __constant_htons(ETH_P_ARP)) {
+		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", htons(arp->ar_pro));
+			return -1;
+		}
+
+		switch (method) {
+		case NAT25_CHECK:
+			return 0;	/* skb_copy for all ARP frame */
+
+		case NAT25_INSERT: {
+			RTW_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: {
+			RTW_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;
+		}
+	}
+
+	/*---------------------------------------------------*/
+	/*         Handle IPX and Apple Talk frame          */
+	/*---------------------------------------------------*/
+	else if ((protocol == __constant_htons(ETH_P_IPX)) ||
+		 (protocol == __constant_htons(ETH_P_ATALK)) ||
+		 (protocol == __constant_htons(ETH_P_AARP))) {
+		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 == __constant_htons(ETH_P_IPX)) {
+			RTW_INFO("NAT25: Protocol=IPX (Ethernet II)\n");
+			ipx = (struct ipxhdr *)framePtr;
+		} else { /* if(protocol <= __constant_htons(ETH_FRAME_LEN)) */
+			if (!memcmp(ipx_header, framePtr, 2)) {
+				RTW_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 */
+
+						RTW_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)) {
+						RTW_INFO("NAT25: Protocol=IPX (Ethernet 802.2)\n");
+						ipx = (struct ipxhdr *)framePtr;
+					} else
+						return -1;
+				}
+			}
+		}
+
+		/*   IPX  */
+		if (ipx != NULL) {
+			switch (method) {
+			case NAT25_CHECK:
+				if (!memcmp(skb->data + ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) {
+					RTW_INFO("NAT25: Check IPX skb_copy\n");
+					return 0;
+				}
+				return -1;
+
+			case NAT25_INSERT: {
+				RTW_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)) {
+					RTW_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)) {
+					RTW_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;
+			}
+		}
+
+		/*   AARP  */
+		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);
+
+				RTW_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: {
+				RTW_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;
+			}
+		}
+
+		/*   DDP  */
+		else if (ddp != NULL) {
+			switch (method) {
+			case NAT25_CHECK:
+				return -1;
+
+			case NAT25_INSERT: {
+				RTW_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: {
+				RTW_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;
+	}
+
+	/*---------------------------------------------------*/
+	/*                Handle PPPoE frame                */
+	/*---------------------------------------------------*/
+	else if ((protocol == __constant_htons(ETH_P_PPP_DISC)) ||
+		 (protocol == __constant_htons(ETH_P_PPP_SES))) {
+		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;
+
+						RTW_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 */
+				RTW_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 == 0) {
+						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);
+
+					RTW_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) {
+					RTW_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;
+		}
+	}
+
+	/*---------------------------------------------------*/
+	/*                 Handle EAP frame                 */
+	/*---------------------------------------------------*/
+	else if (protocol == __constant_htons(0x888e)) {
+		switch (method) {
+		case NAT25_CHECK:
+			return -1;
+
+		case NAT25_INSERT:
+			return 0;
+
+		case NAT25_LOOKUP:
+			return 0;
+
+		default:
+			return -1;
+		}
+	}
+
+	/*---------------------------------------------------*/
+	/*         Handle C-Media proprietary frame         */
+	/*---------------------------------------------------*/
+	else if ((protocol == __constant_htons(0xe2ae)) ||
+		 (protocol == __constant_htons(0xe2af))) {
+		switch (method) {
+		case NAT25_CHECK:
+			return -1;
+
+		case NAT25_INSERT:
+			return 0;
+
+		case NAT25_LOOKUP:
+			return 0;
+
+		default:
+			return -1;
+		}
+	}
+
+	/*---------------------------------------------------*/
+	/*         Handle IPV6 frame      							 */
+	/*---------------------------------------------------*/
+	else if (protocol == __constant_htons(ETH_P_IPV6)) {
+		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: {
+			RTW_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:
+			RTW_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);
+			if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) {
+#ifdef SUPPORT_RX_UNI2MCAST
+				if (iph->daddr.s6_addr[0] == 0xff)
+					convert_ipv6_mac_to_mc(skb);
+#endif
+			}
+			return 0;
+
+		default:
+			return -1;
+		}
+	}
+
+	return -1;
+}
+
+int nat25_handle_frame(_adapter *priv, struct sk_buff *skb)
+{
+
+	if (!(skb->data[0] & 1)) {
+		int is_vlan_tag = 0, i, retval = 0;
+		unsigned short vlan_hdr = 0;
+
+		if (*((unsigned short *)(skb->data + ETH_ALEN * 2)) == __constant_htons(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) {
+			_irqL irqL;
+			_enter_critical_bh(&priv->br_ext_lock, &irqL);
+			/*
+			 *	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 &&
+			    (*((unsigned short *)(skb->data + ETH_ALEN * 2)) == __constant_htons(ETH_P_IP)) &&
+			    !memcmp(priv->scdb_ip, skb->data + ETH_HLEN + 16, 4)) {
+				memcpy(skb->data, priv->scdb_mac, ETH_ALEN);
+
+				_exit_critical_bh(&priv->br_ext_lock, &irqL);
+			} else {
+				_exit_critical_bh(&priv->br_ext_lock, &irqL);
+
+				retval = nat25_db_handle(priv, skb, NAT25_LOOKUP);
+			}
+		} else {
+			if (((*((unsigned short *)(skb->data + ETH_ALEN * 2)) == __constant_htons(ETH_P_IP)) &&
+			     !memcmp(priv->br_ip, skb->data + ETH_HLEN + 16, 4)) ||
+			    ((*((unsigned short *)(skb->data + ETH_ALEN * 2)) == __constant_htons(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));
+			*((unsigned short *)(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(_adapter *priv, struct sk_buff *skb)
+{
+	if (skb == NULL)
+		return;
+
+	if (!priv->ethBrExtInfo.dhcp_bcst_disable) {
+		unsigned short protocol = *((unsigned short *)(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_PTR)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_PTR)udph + sizeof(struct udphdr));
+
+					if (dhcph->cookie == __constant_htonl(DHCP_MAGIC)) { /* match magic word */
+						if (!(dhcph->flags & htons(BROADCAST_FLAG))) { /* if not broadcast */
+							register int sum = 0;
+
+							RTW_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 += dhcph->flags;
+							while (sum >> 16)
+								sum = (sum & 0xffff) + (sum >> 16);
+							udph->check = ~sum;
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+void *scdb_findEntry(_adapter *priv, unsigned char *macAddr,
+		     unsigned char *ipAddr)
+{
+	unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
+	struct nat25_network_db_entry *db;
+	int hash;
+	/* _irqL irqL; */
+	/* _enter_critical_bh(&priv->br_ext_lock, &irqL); */
+
+	__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)) {
+			/* _exit_critical_bh(&priv->br_ext_lock, &irqL); */
+			return (void *)db;
+		}
+
+		db = db->next_hash;
+	}
+
+	/* _exit_critical_bh(&priv->br_ext_lock, &irqL); */
+	return NULL;
+}
+
diff --git a/drivers/staging/rtl8821ce/core/rtw_btcoex.c b/drivers/staging/rtl8821ce/core/rtw_btcoex.c
new file mode 100644
index 000000000000..6abf7db3f012
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/rtw_btcoex.c
@@ -0,0 +1,363 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * Copyright(c) 2013 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 <drv_types.h>
+#include <hal_btcoex.h>
+#include <hal_data.h>
+
+void rtw_btcoex_Initialize(PADAPTER padapter)
+{
+	hal_btcoex_Initialize(padapter);
+}
+
+void rtw_btcoex_PowerOnSetting(PADAPTER padapter)
+{
+	hal_btcoex_PowerOnSetting(padapter);
+}
+
+void rtw_btcoex_PowerOffSetting(PADAPTER padapter)
+{
+	hal_btcoex_PowerOffSetting(padapter);
+}
+
+void rtw_btcoex_HAL_Initialize(PADAPTER padapter, u8 bWifiOnly)
+{
+	hal_btcoex_InitHwConfig(padapter, bWifiOnly);
+}
+
+void rtw_btcoex_IpsNotify(PADAPTER padapter, u8 type)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+	hal_btcoex_IpsNotify(padapter, type);
+}
+
+void rtw_btcoex_LpsNotify(PADAPTER padapter, u8 type)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+	hal_btcoex_LpsNotify(padapter, type);
+}
+
+void rtw_btcoex_ScanNotify(PADAPTER padapter, u8 type)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+	if (_FALSE == type) {
+
+		if (DEV_MGMT_TX_NUM(adapter_to_dvobj(padapter))
+			|| DEV_ROCH_NUM(adapter_to_dvobj(padapter)))
+			return;
+	}
+
+	hal_btcoex_ScanNotify(padapter, type);
+}
+
+void rtw_btcoex_ConnectNotify(PADAPTER padapter, u8 action)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+
+
+	hal_btcoex_ConnectNotify(padapter, action);
+}
+
+void rtw_btcoex_MediaStatusNotify(PADAPTER padapter, u8 mediaStatus)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+
+
+	if ((RT_MEDIA_CONNECT == mediaStatus)
+	    && (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE))
+		rtw_hal_set_hwreg(padapter, HW_VAR_DL_RSVD_PAGE, NULL);
+
+	hal_btcoex_MediaStatusNotify(padapter, mediaStatus);
+}
+
+void rtw_btcoex_SpecialPacketNotify(PADAPTER padapter, u8 pktType)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+	hal_btcoex_SpecialPacketNotify(padapter, pktType);
+}
+
+void rtw_btcoex_BtInfoNotify(PADAPTER padapter, u8 length, u8 *tmpBuf)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+	hal_btcoex_BtInfoNotify(padapter, length, tmpBuf);
+}
+
+void rtw_btcoex_BtMpRptNotify(PADAPTER padapter, u8 length, u8 *tmpBuf)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+	if (padapter->registrypriv.mp_mode == 1)
+		return;
+
+	hal_btcoex_BtMpRptNotify(padapter, length, tmpBuf);
+}
+
+void rtw_btcoex_SuspendNotify(PADAPTER padapter, u8 state)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+	hal_btcoex_SuspendNotify(padapter, state);
+}
+
+void rtw_btcoex_HaltNotify(PADAPTER padapter)
+{
+	PHAL_DATA_TYPE	pHalData;
+	u8 do_halt = 1;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		do_halt = 0;
+
+	if (_FALSE == padapter->bup) {
+		RTW_INFO(FUNC_ADPT_FMT ": bup=%d Skip!\n",
+			 FUNC_ADPT_ARG(padapter), padapter->bup);
+		do_halt = 0;
+	}
+
+	if (rtw_is_surprise_removed(padapter)) {
+		RTW_INFO(FUNC_ADPT_FMT ": bSurpriseRemoved=%s Skip!\n",
+			FUNC_ADPT_ARG(padapter), rtw_is_surprise_removed(padapter) ? "True" : "False");
+		do_halt = 0;
+	}
+
+	hal_btcoex_HaltNotify(padapter, do_halt);
+}
+
+void rtw_btcoex_switchband_notify(u8 under_scan, u8 band_type)
+{
+	hal_btcoex_switchband_notify(under_scan, band_type);
+}
+
+u8 rtw_btcoex_IsBtDisabled(PADAPTER padapter)
+{
+	return hal_btcoex_IsBtDisabled(padapter);
+}
+
+void rtw_btcoex_Handler(PADAPTER padapter)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+	hal_btcoex_Hanlder(padapter);
+}
+
+s32 rtw_btcoex_IsBTCoexRejectAMPDU(PADAPTER padapter)
+{
+	s32 coexctrl;
+
+	coexctrl = hal_btcoex_IsBTCoexRejectAMPDU(padapter);
+
+	return coexctrl;
+}
+
+s32 rtw_btcoex_IsBTCoexCtrlAMPDUSize(PADAPTER padapter)
+{
+	s32 coexctrl;
+
+	coexctrl = hal_btcoex_IsBTCoexCtrlAMPDUSize(padapter);
+
+	return coexctrl;
+}
+
+u32 rtw_btcoex_GetAMPDUSize(PADAPTER padapter)
+{
+	u32 size;
+
+	size = hal_btcoex_GetAMPDUSize(padapter);
+
+	return size;
+}
+
+void rtw_btcoex_SetManualControl(PADAPTER padapter, u8 manual)
+{
+	if (_TRUE == manual)
+		hal_btcoex_SetManualControl(padapter, _TRUE);
+	else
+		hal_btcoex_SetManualControl(padapter, _FALSE);
+}
+
+u8 rtw_btcoex_IsBtControlLps(PADAPTER padapter)
+{
+	return hal_btcoex_IsBtControlLps(padapter);
+}
+
+u8 rtw_btcoex_IsLpsOn(PADAPTER padapter)
+{
+	return hal_btcoex_IsLpsOn(padapter);
+}
+
+u8 rtw_btcoex_RpwmVal(PADAPTER padapter)
+{
+	return hal_btcoex_RpwmVal(padapter);
+}
+
+u8 rtw_btcoex_LpsVal(PADAPTER padapter)
+{
+	return hal_btcoex_LpsVal(padapter);
+}
+
+u32 rtw_btcoex_GetRaMask(PADAPTER padapter)
+{
+	return hal_btcoex_GetRaMask(padapter);
+}
+
+void rtw_btcoex_RecordPwrMode(PADAPTER padapter, u8 *pCmdBuf, u8 cmdLen)
+{
+	hal_btcoex_RecordPwrMode(padapter, pCmdBuf, cmdLen);
+}
+
+/* ==================================================
+ * Below Functions are called by BT-Coex
+ * ================================================== */
+void rtw_btcoex_rx_ampdu_apply(PADAPTER padapter)
+{
+	rtw_rx_ampdu_apply(padapter);
+}
+
+void rtw_btcoex_LPS_Enter(PADAPTER padapter)
+{
+	struct pwrctrl_priv *pwrpriv;
+	u8 lpsVal;
+
+	pwrpriv = adapter_to_pwrctl(padapter);
+
+	pwrpriv->bpower_saving = _TRUE;
+	lpsVal = rtw_btcoex_LpsVal(padapter);
+	rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, lpsVal, "BTCOEX");
+}
+
+u8 rtw_btcoex_LPS_Leave(PADAPTER padapter)
+{
+	struct pwrctrl_priv *pwrpriv;
+
+	pwrpriv = adapter_to_pwrctl(padapter);
+
+	if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) {
+		rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, "BTCOEX");
+		LPS_RF_ON_check(padapter, 100);
+		pwrpriv->bpower_saving = _FALSE;
+	}
+
+	return _TRUE;
+}
+
+u8 rtw_btcoex_get_bt_coexist(PADAPTER padapter)
+{
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+
+	return pHalData->EEPROMBluetoothCoexist;
+}
+
+u8 rtw_btcoex_get_chip_type(PADAPTER padapter)
+{
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+
+	return pHalData->EEPROMBluetoothType;
+}
+
+u8 rtw_btcoex_get_pg_ant_num(PADAPTER padapter)
+{
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+
+	return pHalData->EEPROMBluetoothAntNum == Ant_x2 ? 2 : 1;
+}
+
+u8 rtw_btcoex_get_pg_single_ant_path(PADAPTER padapter)
+{
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+
+	return pHalData->ant_path;
+}
+
+u8 rtw_btcoex_get_pg_rfe_type(PADAPTER padapter)
+{
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+
+	return pHalData->rfe_type;
+}
+
+u8 rtw_btcoex_is_tfbga_package_type(PADAPTER padapter)
+{
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+
+	return _FALSE;
+}
+
+u8 rtw_btcoex_get_ant_div_cfg(PADAPTER padapter)
+{
+	PHAL_DATA_TYPE pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	
+	return (pHalData->AntDivCfg == 0) ? _FALSE : _TRUE;
+}
+
+/* ==================================================
+ * Below Functions are BT-Coex socket related function
+ * ================================================== */
+
diff --git a/drivers/staging/rtl8821ce/core/rtw_btcoex_wifionly.c b/drivers/staging/rtl8821ce/core/rtw_btcoex_wifionly.c
new file mode 100644
index 000000000000..bbbecfbf6177
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/rtw_btcoex_wifionly.c
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * Copyright(c) 2013 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 <drv_types.h>
+#include <hal_btcoex_wifionly.h>
+#include <hal_data.h>
+
+void rtw_btcoex_wifionly_switchband_notify(PADAPTER padapter)
+{
+	hal_btcoex_wifionly_switchband_notify(padapter);
+}
+
+void rtw_btcoex_wifionly_scan_notify(PADAPTER padapter)
+{
+	hal_btcoex_wifionly_scan_notify(padapter);
+}
+
+void rtw_btcoex_wifionly_hw_config(PADAPTER padapter)
+{
+	hal_btcoex_wifionly_hw_config(padapter);
+}
+
+void rtw_btcoex_wifionly_initialize(PADAPTER padapter)
+{
+	hal_btcoex_wifionly_initlizevariables(padapter);
+}
diff --git a/drivers/staging/rtl8821ce/core/rtw_cmd.c b/drivers/staging/rtl8821ce/core/rtw_cmd.c
new file mode 100644
index 000000000000..9df8a03223f8
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/rtw_cmd.c
@@ -0,0 +1,3016 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * 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 <drv_types.h>
+#include <hal_data.h>
+
+#ifndef DBG_CMD_EXECUTE
+	#define DBG_CMD_EXECUTE 0
+#endif
+
+struct cmd_hdl wlancmds[] = {
+	GEN_DRV_CMD_HANDLER(sizeof(struct readMAC_parm), rtw_getmacreg) /*0*/
+	GEN_DRV_CMD_HANDLER(0, NULL)
+	GEN_DRV_CMD_HANDLER(0, NULL)
+	GEN_DRV_CMD_HANDLER(0, NULL)
+	GEN_DRV_CMD_HANDLER(0, NULL)
+	GEN_DRV_CMD_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL) /*10*/
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(sizeof(struct joinbss_parm), join_cmd_hdl)  /*14*/
+	GEN_MLME_EXT_HANDLER(sizeof(struct disconnect_parm), disconnect_hdl)
+	GEN_MLME_EXT_HANDLER(sizeof(struct createbss_parm), createbss_hdl)
+	GEN_MLME_EXT_HANDLER(sizeof(struct setopmode_parm), setopmode_hdl)
+	GEN_MLME_EXT_HANDLER(sizeof(struct sitesurvey_parm), sitesurvey_cmd_hdl)  /*18*/
+	GEN_MLME_EXT_HANDLER(sizeof(struct setauth_parm), setauth_hdl)
+	GEN_MLME_EXT_HANDLER(sizeof(struct setkey_parm), setkey_hdl)  /*20*/
+	GEN_MLME_EXT_HANDLER(sizeof(struct set_stakey_parm), set_stakey_hdl)
+	GEN_MLME_EXT_HANDLER(sizeof(struct set_assocsta_parm), NULL)
+	GEN_MLME_EXT_HANDLER(sizeof(struct del_assocsta_parm), NULL)
+	GEN_MLME_EXT_HANDLER(sizeof(struct setstapwrstate_parm), NULL)
+	GEN_MLME_EXT_HANDLER(sizeof(struct setbasicrate_parm), NULL)
+	GEN_MLME_EXT_HANDLER(sizeof(struct getbasicrate_parm), NULL)
+	GEN_MLME_EXT_HANDLER(sizeof(struct setdatarate_parm), NULL)
+	GEN_MLME_EXT_HANDLER(sizeof(struct getdatarate_parm), NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)   /*30*/
+	GEN_MLME_EXT_HANDLER(sizeof(struct setphy_parm), NULL)
+	GEN_MLME_EXT_HANDLER(sizeof(struct getphy_parm), NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)	/*40*/
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(sizeof(struct addBaReq_parm), add_ba_hdl)
+	GEN_MLME_EXT_HANDLER(sizeof(struct set_ch_parm), set_ch_hdl) /* 46 */
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL) /*50*/
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(sizeof(struct Tx_Beacon_param), tx_beacon_hdl) /*55*/
+
+	GEN_MLME_EXT_HANDLER(0, mlme_evt_hdl) /*56*/
+	GEN_MLME_EXT_HANDLER(0, rtw_drvextra_cmd_hdl) /*57*/
+
+	GEN_MLME_EXT_HANDLER(0, h2c_msg_hdl) /*58*/
+	GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelPlan_param), set_chplan_hdl) /*59*/
+	GEN_MLME_EXT_HANDLER(sizeof(struct LedBlink_param), led_blink_hdl) /*60*/
+
+	GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelSwitch_param), set_csa_hdl) /*61*/
+	GEN_MLME_EXT_HANDLER(sizeof(struct TDLSoption_param), tdls_hdl) /*62*/
+	GEN_MLME_EXT_HANDLER(0, chk_bmc_sleepq_hdl) /*63*/
+	GEN_MLME_EXT_HANDLER(sizeof(struct RunInThread_param), run_in_thread_hdl) /*64*/
+	GEN_MLME_EXT_HANDLER(sizeof(struct addBaRsp_parm), add_ba_rsp_hdl) /* 65 */
+};
+
+struct _cmd_callback	rtw_cmd_callback[] = {
+	{GEN_CMD_CODE(_Read_MACREG), &rtw_getmacreg_cmdrsp_callback}, /*0*/
+	{GEN_CMD_CODE(_Write_MACREG), NULL},
+	{GEN_CMD_CODE(_Read_BBREG), &rtw_getbbrfreg_cmdrsp_callback},
+	{GEN_CMD_CODE(_Write_BBREG), NULL},
+	{GEN_CMD_CODE(_Read_RFREG), &rtw_getbbrfreg_cmdrsp_callback},
+	{GEN_CMD_CODE(_Write_RFREG), NULL}, /*5*/
+	{GEN_CMD_CODE(_Read_EEPROM), NULL},
+	{GEN_CMD_CODE(_Write_EEPROM), NULL},
+	{GEN_CMD_CODE(_Read_EFUSE), NULL},
+	{GEN_CMD_CODE(_Write_EFUSE), NULL},
+
+	{GEN_CMD_CODE(_Read_CAM),	NULL},	/*10*/
+	{GEN_CMD_CODE(_Write_CAM),	 NULL},
+	{GEN_CMD_CODE(_setBCNITV), NULL},
+	{GEN_CMD_CODE(_setMBIDCFG), NULL},
+	{GEN_CMD_CODE(_JoinBss), &rtw_joinbss_cmd_callback},  /*14*/
+	{GEN_CMD_CODE(_DisConnect), &rtw_disassoc_cmd_callback}, /*15*/
+	{GEN_CMD_CODE(_CreateBss), NULL},
+	{GEN_CMD_CODE(_SetOpMode), NULL},
+	{GEN_CMD_CODE(_SiteSurvey), &rtw_survey_cmd_callback}, /*18*/
+	{GEN_CMD_CODE(_SetAuth), NULL},
+
+	{GEN_CMD_CODE(_SetKey), NULL},	/*20*/
+	{GEN_CMD_CODE(_SetStaKey), &rtw_setstaKey_cmdrsp_callback},
+	{GEN_CMD_CODE(_SetAssocSta), &rtw_setassocsta_cmdrsp_callback},
+	{GEN_CMD_CODE(_DelAssocSta), NULL},
+	{GEN_CMD_CODE(_SetStaPwrState), NULL},
+	{GEN_CMD_CODE(_SetBasicRate), NULL}, /*25*/
+	{GEN_CMD_CODE(_GetBasicRate), NULL},
+	{GEN_CMD_CODE(_SetDataRate), NULL},
+	{GEN_CMD_CODE(_GetDataRate), NULL},
+	{GEN_CMD_CODE(_SetPhyInfo), NULL},
+
+	{GEN_CMD_CODE(_GetPhyInfo), NULL}, /*30*/
+	{GEN_CMD_CODE(_SetPhy), NULL},
+	{GEN_CMD_CODE(_GetPhy), NULL},
+	{GEN_CMD_CODE(_readRssi), NULL},
+	{GEN_CMD_CODE(_readGain), NULL},
+	{GEN_CMD_CODE(_SetAtim), NULL}, /*35*/
+	{GEN_CMD_CODE(_SetPwrMode), NULL},
+	{GEN_CMD_CODE(_JoinbssRpt), NULL},
+	{GEN_CMD_CODE(_SetRaTable), NULL},
+	{GEN_CMD_CODE(_GetRaTable) , NULL},
+
+	{GEN_CMD_CODE(_GetCCXReport), NULL}, /*40*/
+	{GEN_CMD_CODE(_GetDTMReport),	NULL},
+	{GEN_CMD_CODE(_GetTXRateStatistics), NULL},
+	{GEN_CMD_CODE(_SetUsbSuspend), NULL},
+	{GEN_CMD_CODE(_SetH2cLbk), NULL},
+	{GEN_CMD_CODE(_AddBAReq), NULL}, /*45*/
+	{GEN_CMD_CODE(_SetChannel), NULL},		/*46*/
+	{GEN_CMD_CODE(_SetTxPower), NULL},
+	{GEN_CMD_CODE(_SwitchAntenna), NULL},
+	{GEN_CMD_CODE(_SetCrystalCap), NULL},
+	{GEN_CMD_CODE(_SetSingleCarrierTx), NULL},	/*50*/
+
+	{GEN_CMD_CODE(_SetSingleToneTx), NULL}, /*51*/
+	{GEN_CMD_CODE(_SetCarrierSuppressionTx), NULL},
+	{GEN_CMD_CODE(_SetContinuousTx), NULL},
+	{GEN_CMD_CODE(_SwitchBandwidth), NULL},		/*54*/
+	{GEN_CMD_CODE(_TX_Beacon), NULL},/*55*/
+
+	{GEN_CMD_CODE(_Set_MLME_EVT), NULL},/*56*/
+	{GEN_CMD_CODE(_Set_Drv_Extra), NULL},/*57*/
+	{GEN_CMD_CODE(_Set_H2C_MSG), NULL},/*58*/
+	{GEN_CMD_CODE(_SetChannelPlan), NULL},/*59*/
+	{GEN_CMD_CODE(_LedBlink), NULL},/*60*/
+
+	{GEN_CMD_CODE(_SetChannelSwitch), NULL},/*61*/
+	{GEN_CMD_CODE(_TDLS), NULL},/*62*/
+	{GEN_CMD_CODE(_ChkBMCSleepq), NULL}, /*63*/
+
+	{GEN_CMD_CODE(_RunInThreadCMD), NULL},/*64*/
+	{GEN_CMD_CODE(_AddBARsp), NULL}, /*65*/
+};
+
+/*
+Caller and the rtw_cmd_thread can protect cmd_q by spin_lock.
+No irqsave is necessary.
+*/
+
+sint	_rtw_init_cmd_priv(struct	cmd_priv *pcmdpriv)
+{
+	sint res = _SUCCESS;
+
+	_rtw_init_sema(&(pcmdpriv->cmd_queue_sema), 0);
+	/* _rtw_init_sema(&(pcmdpriv->cmd_done_sema), 0); */
+	/*_rtw_init_sema(&(pcmdpriv->terminate_cmdthread_sema), 0);*/
+	_rtw_init_sema(&(pcmdpriv->start_cmdthread_sema), 0);
+	_rtw_init_completion(&pcmdpriv->cmdthread_comp);
+
+	_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 = rtw_zmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ);
+
+	if (pcmdpriv->cmd_allocated_buf == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf  +  CMDBUFF_ALIGN_SZ - ((SIZE_PTR)(pcmdpriv->cmd_allocated_buf) & (CMDBUFF_ALIGN_SZ - 1));
+
+	pcmdpriv->rsp_allocated_buf = rtw_zmalloc(MAX_RSPSZ + 4);
+
+	if (pcmdpriv->rsp_allocated_buf == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf  +  4 - ((SIZE_PTR)(pcmdpriv->rsp_allocated_buf) & 3);
+
+	pcmdpriv->cmd_issued_cnt = pcmdpriv->cmd_done_cnt = pcmdpriv->rsp_cnt = 0;
+
+	_rtw_mutex_init(&pcmdpriv->sctx_mutex);
+exit:
+
+	return res;
+
+}
+
+
+sint _rtw_init_evt_priv(struct evt_priv *pevtpriv)
+{
+	sint 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;
+
+
+
+	return res;
+}
+
+void _rtw_free_evt_priv(struct	evt_priv *pevtpriv)
+{
+
+
+
+}
+
+void _rtw_free_cmd_priv(struct	cmd_priv *pcmdpriv)
+{
+
+	if (pcmdpriv) {
+		_rtw_spinlock_free(&(pcmdpriv->cmd_queue.lock));
+		_rtw_free_sema(&(pcmdpriv->cmd_queue_sema));
+		/* _rtw_free_sema(&(pcmdpriv->cmd_done_sema)); */
+		/*_rtw_free_sema(&(pcmdpriv->terminate_cmdthread_sema));*/
+		_rtw_free_sema(&(pcmdpriv->start_cmdthread_sema));
+
+		if (pcmdpriv->cmd_allocated_buf)
+			rtw_mfree(pcmdpriv->cmd_allocated_buf, MAX_CMDSZ + CMDBUFF_ALIGN_SZ);
+
+		if (pcmdpriv->rsp_allocated_buf)
+			rtw_mfree(pcmdpriv->rsp_allocated_buf, MAX_RSPSZ + 4);
+
+		_rtw_mutex_free(&pcmdpriv->sctx_mutex);
+	}
+}
+
+/*
+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.
+
+*/
+
+sint _rtw_enqueue_cmd(_queue *queue, struct cmd_obj *obj, bool to_head)
+{
+	_irqL irqL;
+
+	if (obj == NULL)
+		goto exit;
+
+	/* _enter_critical_bh(&queue->lock, &irqL); */
+	_enter_critical(&queue->lock, &irqL);
+
+	if (to_head)
+		rtw_list_insert_head(&obj->list, &queue->queue);
+	else
+		rtw_list_insert_tail(&obj->list, &queue->queue);
+
+
+	/* _exit_critical_bh(&queue->lock, &irqL);	 */
+	_exit_critical(&queue->lock, &irqL);
+
+exit:
+
+	return _SUCCESS;
+}
+
+struct	cmd_obj	*_rtw_dequeue_cmd(_queue *queue)
+{
+	_irqL irqL;
+	struct cmd_obj *obj;
+
+	/* _enter_critical_bh(&(queue->lock), &irqL); */
+	_enter_critical(&queue->lock, &irqL);
+
+
+	if (rtw_is_list_empty(&(queue->queue)))
+		obj = NULL;
+	else {
+		obj = LIST_CONTAINOR(get_next(&(queue->queue)), struct cmd_obj, list);
+
+
+		rtw_list_delete(&obj->list);
+	}
+
+	/* _exit_critical_bh(&(queue->lock), &irqL); */
+	_exit_critical(&queue->lock, &irqL);
+
+	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_evt_priv(struct	evt_priv *pevtpriv)
+{
+	_rtw_free_evt_priv(pevtpriv);
+}
+
+void rtw_free_cmd_priv(struct	cmd_priv *pcmdpriv)
+{
+	_rtw_free_cmd_priv(pcmdpriv);
+}
+
+int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj);
+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 */
+
+
+	if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan))
+		bAllow = _TRUE;
+
+	if (cmd_obj->no_io)
+		bAllow = _TRUE;
+
+	if ((!rtw_is_hw_init_completed(pcmdpriv->padapter) && (bAllow == _FALSE))
+	    || ATOMIC_READ(&(pcmdpriv->cmdthd_running)) == _FALSE	/* com_thread not running */
+	   ) {
+		if (DBG_CMD_EXECUTE)
+			RTW_INFO(ADPT_FMT" drop "CMD_FMT" hw_init_completed:%u, cmdthd_running:%u\n", ADPT_ARG(cmd_obj->padapter)
+				, CMD_ARG(cmd_obj), rtw_get_hw_init_completed(cmd_obj->padapter), ATOMIC_READ(&pcmdpriv->cmdthd_running));
+		if (0)
+			rtw_warn_on(1);
+
+		return _FAIL;
+	}
+	return _SUCCESS;
+}
+
+u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
+{
+	int res = _FAIL;
+	PADAPTER padapter = pcmdpriv->padapter;
+
+	if (cmd_obj == NULL)
+		goto exit;
+
+	cmd_obj->padapter = padapter;
+
+
+	res = rtw_cmd_filter(pcmdpriv, cmd_obj);
+	if ((_FAIL == res) || (cmd_obj->cmdsz > MAX_CMDSZ)) {
+		if (cmd_obj->cmdsz > MAX_CMDSZ) {
+			RTW_INFO("%s failed due to obj->cmdsz(%d) > MAX_CMDSZ(%d)\n", __func__, cmd_obj->cmdsz, MAX_CMDSZ);
+			rtw_warn_on(1);
+		}
+
+		if (cmd_obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) {
+			struct drvextra_cmd_parm *extra_parm = (struct drvextra_cmd_parm *)cmd_obj->parmbuf;
+
+			if (extra_parm->pbuf && extra_parm->size > 0)
+				rtw_mfree(extra_parm->pbuf, extra_parm->size);
+		}
+		rtw_free_cmd_obj(cmd_obj);
+		goto exit;
+	}
+
+	res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj, 0);
+
+	if (res == _SUCCESS)
+		_rtw_up_sema(&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_free_cmd_obj(struct cmd_obj *pcmd)
+{
+	struct drvextra_cmd_parm *extra_parm = NULL;
+
+	if (pcmd->parmbuf != NULL) {
+		/* free parmbuf in cmd_obj */
+		rtw_mfree((unsigned char *)pcmd->parmbuf, pcmd->cmdsz);
+	}
+	if (pcmd->rsp != NULL) {
+		if (pcmd->rspsz != 0) {
+			/* free rsp in cmd_obj */
+			rtw_mfree((unsigned char *)pcmd->rsp, pcmd->rspsz);
+		}
+	}
+
+	/* free cmd_obj */
+	rtw_mfree((unsigned char *)pcmd, sizeof(struct cmd_obj));
+
+}
+
+void rtw_stop_cmd_thread(_adapter *adapter)
+{
+	if (adapter->cmdThread &&
+	    ATOMIC_READ(&(adapter->cmdpriv.cmdthd_running)) == _TRUE &&
+	    adapter->cmdpriv.stop_req == 0) {
+		adapter->cmdpriv.stop_req = 1;
+		_rtw_up_sema(&adapter->cmdpriv.cmd_queue_sema);
+		/*_rtw_down_sema(&adapter->cmdpriv.terminate_cmdthread_sema);*/
+		rtw_wait_for_thread_stop(&adapter->cmdpriv.cmdthread_comp);
+	}
+}
+
+thread_return rtw_cmd_thread(thread_context context)
+{
+	u8 ret;
+	struct cmd_obj *pcmd;
+	u8 *pcmdbuf, *prspbuf;
+	u32 cmd_start_time;
+	u32 cmd_process_time;
+	u8(*cmd_hdl)(_adapter *padapter, u8 *pbuf);
+	void (*pcmd_callback)(_adapter *dev, struct cmd_obj *pcmd);
+	PADAPTER padapter = (PADAPTER)context;
+	struct cmd_priv *pcmdpriv = &(padapter->cmdpriv);
+	struct drvextra_cmd_parm *extra_parm = NULL;
+	_irqL irqL;
+
+	thread_enter("RTW_CMD_THREAD");
+
+	pcmdbuf = pcmdpriv->cmd_buf;
+	prspbuf = pcmdpriv->rsp_buf;
+
+	pcmdpriv->stop_req = 0;
+	ATOMIC_SET(&(pcmdpriv->cmdthd_running), _TRUE);
+	/*_rtw_up_sema(&pcmdpriv->terminate_cmdthread_sema);*/
+	_rtw_up_sema(&pcmdpriv->start_cmdthread_sema);
+
+	while (1) {
+		if (_rtw_down_sema(&pcmdpriv->cmd_queue_sema) == _FAIL) {
+			RTW_PRINT(FUNC_ADPT_FMT" _rtw_down_sema(&pcmdpriv->cmd_queue_sema) return _FAIL, break\n", FUNC_ADPT_ARG(padapter));
+			break;
+		}
+
+		if (RTW_CANNOT_RUN(padapter)) {
+			RTW_PRINT("%s: DriverStopped(%s) SurpriseRemoved(%s) break at line %d\n",
+				  __func__
+				, rtw_is_drv_stopped(padapter) ? "True" : "False"
+				, rtw_is_surprise_removed(padapter) ? "True" : "False"
+				  , __LINE__);
+			break;
+		}
+
+		if (pcmdpriv->stop_req) {
+			RTW_PRINT(FUNC_ADPT_FMT" stop_req:%u, break\n", FUNC_ADPT_ARG(padapter), pcmdpriv->stop_req);
+			break;
+		}
+
+		_enter_critical(&pcmdpriv->cmd_queue.lock, &irqL);
+		if (rtw_is_list_empty(&(pcmdpriv->cmd_queue.queue))) {
+			/* RTW_INFO("%s: cmd queue is empty!\n", __func__); */
+			_exit_critical(&pcmdpriv->cmd_queue.lock, &irqL);
+			continue;
+		}
+		_exit_critical(&pcmdpriv->cmd_queue.lock, &irqL);
+
+_next:
+		if (RTW_CANNOT_RUN(padapter)) {
+			RTW_PRINT("%s: DriverStopped(%s) SurpriseRemoved(%s) break at line %d\n",
+				  __func__
+				, rtw_is_drv_stopped(padapter) ? "True" : "False"
+				, rtw_is_surprise_removed(padapter) ? "True" : "False"
+				  , __LINE__);
+			break;
+		}
+
+		pcmd = rtw_dequeue_cmd(pcmdpriv);
+		if (!pcmd) {
+			continue;
+		}
+
+		cmd_start_time = rtw_get_current_time();
+		pcmdpriv->cmd_issued_cnt++;
+
+		if (pcmd->cmdsz > MAX_CMDSZ) {
+			RTW_ERR("%s cmdsz:%d > MAX_CMDSZ:%d\n", __func__, pcmd->cmdsz, MAX_CMDSZ);
+			pcmd->res = H2C_PARAMETERS_ERROR;
+			goto post_process;
+		}
+
+		if (pcmd->cmdcode >= (sizeof(wlancmds) / sizeof(struct cmd_hdl))) {
+			RTW_ERR("%s undefined cmdcode:%d\n", __func__, pcmd->cmdcode);
+			pcmd->res = H2C_PARAMETERS_ERROR;
+			goto post_process;
+		}
+
+		cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns;
+		if (!cmd_hdl) {
+			RTW_ERR("%s no cmd_hdl for cmdcode:%d\n", __func__, pcmd->cmdcode);
+			pcmd->res = H2C_PARAMETERS_ERROR;
+			goto post_process;
+		}
+
+		if (_FAIL == rtw_cmd_filter(pcmdpriv, pcmd)) {
+			pcmd->res = H2C_DROPPED;
+			if (pcmd->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) {
+				extra_parm = (struct drvextra_cmd_parm *)pcmd->parmbuf;
+				if (extra_parm && extra_parm->pbuf && extra_parm->size > 0)
+					rtw_mfree(extra_parm->pbuf, extra_parm->size);
+			}
+			goto post_process;
+		}
+
+
+		if (DBG_CMD_EXECUTE)
+			RTW_INFO(ADPT_FMT" "CMD_FMT" %sexecute\n", ADPT_ARG(pcmd->padapter), CMD_ARG(pcmd)
+				, pcmd->res == H2C_ENQ_HEAD ? "ENQ_HEAD " : (pcmd->res == H2C_ENQ_HEAD_FAIL ? "ENQ_HEAD_FAIL " : ""));
+
+		_rtw_memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz);
+		ret = cmd_hdl(pcmd->padapter, pcmdbuf);
+		pcmd->res = ret;
+
+		pcmdpriv->cmd_seq++;
+
+post_process:
+
+		_enter_critical_mutex(&(pcmd->padapter->cmdpriv.sctx_mutex), NULL);
+		if (pcmd->sctx) {
+			if (0)
+				RTW_PRINT(FUNC_ADPT_FMT" pcmd->sctx\n", FUNC_ADPT_ARG(pcmd->padapter));
+			if (pcmd->res == H2C_SUCCESS)
+				rtw_sctx_done(&pcmd->sctx);
+			else
+				rtw_sctx_done_err(&pcmd->sctx, RTW_SCTX_DONE_CMD_ERROR);
+		}
+		_exit_critical_mutex(&(pcmd->padapter->cmdpriv.sctx_mutex), NULL);
+
+		cmd_process_time = rtw_get_passing_time_ms(cmd_start_time);
+		if (cmd_process_time > 1000) {
+			RTW_INFO(ADPT_FMT" "CMD_FMT" process_time=%d\n", ADPT_ARG(pcmd->padapter), CMD_ARG(pcmd), cmd_process_time);
+			if (0)
+				rtw_warn_on(1);
+		}
+
+		/* call callback function for post-processed */
+		if (pcmd->cmdcode < (sizeof(rtw_cmd_callback) / sizeof(struct _cmd_callback))) {
+			pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback;
+			if (pcmd_callback == NULL) {
+				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 {
+			rtw_free_cmd_obj(pcmd);
+		}
+
+		flush_signals_thread();
+
+		goto _next;
+
+	}
+
+
+	/* to avoid enqueue cmd after free all cmd_obj */
+	ATOMIC_SET(&(pcmdpriv->cmdthd_running), _FALSE);
+
+	/* free all cmd_obj resources */
+	do {
+		pcmd = rtw_dequeue_cmd(pcmdpriv);
+		if (pcmd == NULL)
+			break;
+
+		if (0)
+			RTW_INFO("%s: leaving... drop "CMD_FMT"\n", __func__, CMD_ARG(pcmd));
+
+		if (pcmd->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) {
+			extra_parm = (struct drvextra_cmd_parm *)pcmd->parmbuf;
+			if (extra_parm->pbuf && extra_parm->size > 0)
+				rtw_mfree(extra_parm->pbuf, extra_parm->size);
+		}
+
+		_enter_critical_mutex(&(pcmd->padapter->cmdpriv.sctx_mutex), NULL);
+		if (pcmd->sctx) {
+			if (0)
+				RTW_PRINT(FUNC_ADPT_FMT" pcmd->sctx\n", FUNC_ADPT_ARG(pcmd->padapter));
+			rtw_sctx_done_err(&pcmd->sctx, RTW_SCTX_DONE_CMD_DROP);
+		}
+		_exit_critical_mutex(&(pcmd->padapter->cmdpriv.sctx_mutex), NULL);
+
+		rtw_free_cmd_obj(pcmd);
+	} while (1);
+
+	/*_rtw_up_sema(&pcmdpriv->terminate_cmdthread_sema);*/
+	thread_exit(&pcmdpriv->cmdthread_comp);
+	return 0;
+}
+
+/*
+rtw_sitesurvey_cmd(~)
+	### NOTE:#### (!!!!)
+	MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock
+*/
+u8 rtw_sitesurvey_cmd(_adapter  *padapter, 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;
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	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 = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL)
+		return _FAIL;
+
+	psurveyPara = (struct sitesurvey_parm *)rtw_zmalloc(sizeof(struct sitesurvey_parm));
+	if (psurveyPara == NULL) {
+		rtw_mfree((unsigned char *) ph2c, sizeof(struct cmd_obj));
+		return _FAIL;
+	}
+
+	rtw_free_network_queue(padapter, _FALSE);
+
+	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) {
+				_rtw_memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(NDIS_802_11_SSID));
+				psurveyPara->ssid_num++;
+				if (0)
+					RTW_INFO(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)) {
+				_rtw_memcpy(&psurveyPara->ch[i], &ch[i], sizeof(struct rtw_ieee80211_channel));
+				psurveyPara->ch_num++;
+				if (0)
+					RTW_INFO(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 = rtw_get_current_time();
+
+			mlme_set_scan_to_timer(pmlmepriv, SCANNING_TIMEOUT);
+
+		rtw_led_control(padapter, LED_CTL_SITE_SURVEY);
+	} else
+		_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+
+	return res;
+}
+
+u8 rtw_setdatarate_cmd(_adapter *padapter, u8 *rateset)
+{
+	struct cmd_obj			*ph2c;
+	struct setdatarate_parm	*pbsetdataratepara;
+	struct cmd_priv		*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pbsetdataratepara = (struct setdatarate_parm *)rtw_zmalloc(sizeof(struct setdatarate_parm));
+	if (pbsetdataratepara == NULL) {
+		rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara, GEN_CMD_CODE(_SetDataRate));
+	pbsetdataratepara->mac_id = 5;
+	_rtw_memcpy(pbsetdataratepara->datarates, rateset, NumRates);
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+	return res;
+}
+
+void rtw_getbbrfreg_cmdrsp_callback(_adapter	*padapter,  struct cmd_obj *pcmd)
+{
+
+	/* rtw_free_cmd_obj(pcmd); */
+	rtw_mfree((unsigned char *) pcmd->parmbuf, pcmd->cmdsz);
+	rtw_mfree((unsigned char *) pcmd, sizeof(struct cmd_obj));
+
+	if (padapter->registrypriv.mp_mode == 1)
+		padapter->mppriv.workparam.bcompleted = _TRUE;
+}
+
+static u8 rtw_createbss_cmd(_adapter  *adapter, int flags, bool adhoc
+			    , s16 req_ch, s8 req_bw, s8 req_offset)
+{
+	struct cmd_obj *cmdobj;
+	struct createbss_parm *parm;
+	struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
+	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	struct submit_ctx sctx;
+	u8 res = _SUCCESS;
+
+	if (req_ch > 0 && req_bw >= 0 && req_offset >= 0) {
+		if (!rtw_chset_is_chbw_valid(adapter->mlmeextpriv.channel_set, req_ch, req_bw, req_offset)) {
+			res = _FAIL;
+			goto exit;
+		}
+	}
+
+	/* prepare cmd parameter */
+	parm = (struct createbss_parm *)rtw_zmalloc(sizeof(*parm));
+	if (parm == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	if (adhoc) {
+		/* for now, adhoc doesn't support ch,bw,offset request */
+		parm->adhoc = 1;
+	} else {
+		parm->adhoc = 0;
+		parm->req_ch = req_ch;
+		parm->req_bw = req_bw;
+		parm->req_offset = req_offset;
+	}
+
+	if (flags & RTW_CMDF_DIRECTLY) {
+		/* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+		if (H2C_SUCCESS != createbss_hdl(adapter, (u8 *)parm))
+			res = _FAIL;
+		rtw_mfree((u8 *)parm, sizeof(*parm));
+	} else {
+		/* need enqueue, prepare cmd_obj and enqueue */
+		cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj));
+		if (cmdobj == NULL) {
+			res = _FAIL;
+			rtw_mfree((u8 *)parm, sizeof(*parm));
+			goto exit;
+		}
+
+		init_h2fwcmd_w_parm_no_rsp(cmdobj, parm, GEN_CMD_CODE(_CreateBss));
+
+		if (flags & RTW_CMDF_WAIT_ACK) {
+			cmdobj->sctx = &sctx;
+			rtw_sctx_init(&sctx, 2000);
+		}
+
+		res = rtw_enqueue_cmd(pcmdpriv, cmdobj);
+
+		if (res == _SUCCESS && (flags & RTW_CMDF_WAIT_ACK)) {
+			rtw_sctx_wait(&sctx, __func__);
+			_enter_critical_mutex(&pcmdpriv->sctx_mutex, NULL);
+			if (sctx.status == RTW_SCTX_SUBMITTED)
+				cmdobj->sctx = NULL;
+			_exit_critical_mutex(&pcmdpriv->sctx_mutex, NULL);
+		}
+	}
+
+exit:
+	return res;
+}
+
+inline u8 rtw_create_ibss_cmd(_adapter *adapter, int flags)
+{
+	return rtw_createbss_cmd(adapter, flags
+		, 1
+		, 0, -1, -1 /* for now, adhoc doesn't support ch,bw,offset request */
+	);
+}
+
+inline u8 rtw_startbss_cmd(_adapter *adapter, int flags)
+{
+	return rtw_createbss_cmd(adapter, flags
+		, 0
+		, 0, -1, -1 /* excute entire AP setup cmd */
+	);
+}
+
+u8 rtw_joinbss_cmd(_adapter  *padapter, struct wlan_network *pnetwork)
+{
+	u8	*auth, res = _SUCCESS;
+	uint	t_len = 0;
+	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;
+	struct vht_priv		*pvhtpriv = &pmlmepriv->vhtpriv;
+	NDIS_802_11_NETWORK_INFRASTRUCTURE ndis_network_mode = pnetwork->network.InfrastructureMode;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u32 tmp_len;
+	u8 *ptmp = NULL;
+
+	rtw_led_control(padapter, LED_CTL_START_TO_LINK);
+
+	pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (pcmd == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	/* for IEs is fix buf size */
+	t_len = sizeof(WLAN_BSSID_EX);
+
+	/* for hidden ap to set fw_state here */
+	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) != _TRUE) {
+		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:
+		case Ndis802_11Monitor:
+			break;
+
+		}
+	}
+
+	pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->network.IEs, pnetwork->network.IELength);
+
+	/*
+		Modified by Arvin 2015/05/13
+		Solution for allocating a new WLAN_BSSID_EX to avoid race condition issue between disconnect and joinbss
+	*/
+	psecnetwork = (WLAN_BSSID_EX *)rtw_zmalloc(sizeof(WLAN_BSSID_EX));
+	if (psecnetwork == NULL) {
+		if (pcmd != NULL)
+			rtw_mfree((unsigned char *)pcmd, sizeof(struct	cmd_obj));
+
+		res = _FAIL;
+
+		goto exit;
+	}
+
+	_rtw_memset(psecnetwork, 0, t_len);
+
+	_rtw_memcpy(psecnetwork, &pnetwork->network, get_WLAN_BSSID_EX_sz(&pnetwork->network));
+
+	auth = &psecuritypriv->authenticator_ie[0];
+	psecuritypriv->authenticator_ie[0] = (unsigned char)psecnetwork->IELength;
+
+	if ((psecnetwork->IELength - 12) < (256 - 1))
+		_rtw_memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], psecnetwork->IELength - 12);
+	else
+		_rtw_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 == _FALSE)
+		_rtw_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) {
+		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;
+	ptmp = rtw_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_, &tmp_len, pnetwork->network.IELength - 12);
+	if (pregistrypriv->ht_enable && ptmp && tmp_len > 0) {
+		/*	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_ht_use_default_setting(padapter);
+
+			rtw_build_wmm_ie_ht(padapter, &psecnetwork->IEs[0], &psecnetwork->IELength);
+
+			/* rtw_restructure_ht_ie */
+			rtw_restructure_ht_ie(padapter, &pnetwork->network.IEs[12], &psecnetwork->IEs[0],
+				pnetwork->network.IELength - 12, &psecnetwork->IELength,
+				pnetwork->network.Configuration.DSConfig);
+		}
+	}
+
+	pvhtpriv->vht_option = _FALSE;
+	if (phtpriv->ht_option
+	    && REGSTY_IS_11AC_ENABLE(pregistrypriv)
+	    && hal_chk_proto_cap(padapter, PROTO_CAP_11AC)
+	    && (!pmlmepriv->country_ent || COUNTRY_CHPLAN_EN_11AC(pmlmepriv->country_ent))
+	   ) {
+		rtw_restructure_vht_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0],
+			pnetwork->network.IELength, &psecnetwork->IELength);
+	}
+
+	rtw_append_exented_cap(padapter, &psecnetwork->IEs[0], &psecnetwork->IELength);
+
+
+	pcmd->cmdsz = sizeof(WLAN_BSSID_EX);
+
+	_rtw_init_listhead(&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(_adapter *padapter, u32 deauth_timeout_ms, int flags) /* for sta_mode */
+{
+	struct cmd_obj *cmdobj = NULL;
+	struct disconnect_parm *param = NULL;
+	struct cmd_priv *cmdpriv = &padapter->cmdpriv;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	struct submit_ctx sctx;
+	u8 res = _SUCCESS;
+
+	/* prepare cmd parameter */
+	param = (struct disconnect_parm *)rtw_zmalloc(sizeof(*param));
+	if (param == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	param->deauth_timeout_ms = deauth_timeout_ms;
+
+	if (flags & RTW_CMDF_DIRECTLY) {
+		/* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+		if (disconnect_hdl(padapter, (u8 *)param) != H2C_SUCCESS)
+			res = _FAIL;
+		rtw_mfree((u8 *)param, sizeof(*param));
+
+	} else {
+		cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj));
+		if (cmdobj == NULL) {
+			res = _FAIL;
+			rtw_mfree((u8 *)param, sizeof(*param));
+			goto exit;
+		}
+		init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_);
+		if (flags & RTW_CMDF_WAIT_ACK) {
+			cmdobj->sctx = &sctx;
+			rtw_sctx_init(&sctx, 2000);
+		}
+		res = rtw_enqueue_cmd(cmdpriv, cmdobj);
+		if (res == _SUCCESS && (flags & RTW_CMDF_WAIT_ACK)) {
+			rtw_sctx_wait(&sctx, __func__);
+			_enter_critical_mutex(&pcmdpriv->sctx_mutex, NULL);
+			if (sctx.status == RTW_SCTX_SUBMITTED)
+				cmdobj->sctx = NULL;
+			_exit_critical_mutex(&pcmdpriv->sctx_mutex, NULL);
+		}
+	}
+
+exit:
+
+	return res;
+}
+
+u8 rtw_setopmode_cmd(_adapter  *padapter, NDIS_802_11_NETWORK_INFRASTRUCTURE networktype, bool enqueue)
+{
+	struct	cmd_obj	*ph2c;
+	struct	setopmode_parm *psetop;
+
+	struct	cmd_priv   *pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	psetop = (struct setopmode_parm *)rtw_zmalloc(sizeof(struct setopmode_parm));
+
+	if (psetop == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	psetop->mode = (u8)networktype;
+
+	if (enqueue) {
+		ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+		if (ph2c == NULL) {
+			rtw_mfree((u8 *)psetop, sizeof(*psetop));
+			res = _FAIL;
+			goto exit;
+		}
+
+		init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
+		res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	} else {
+		setopmode_hdl(padapter, (u8 *)psetop);
+		rtw_mfree((u8 *)psetop, sizeof(*psetop));
+	}
+exit:
+
+	return res;
+}
+
+u8 rtw_setstakey_cmd(_adapter *padapter, struct sta_info *sta, u8 key_type, bool 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 mlme_priv			*pmlmepriv = &padapter->mlmepriv;
+	struct security_priv		*psecuritypriv = &padapter->securitypriv;
+	u8	res = _SUCCESS;
+
+	psetstakey_para = (struct set_stakey_parm *)rtw_zmalloc(sizeof(struct set_stakey_parm));
+	if (psetstakey_para == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	_rtw_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 (key_type == GROUP_KEY)
+		_rtw_memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16);
+	else if (key_type == UNICAST_KEY)
+		_rtw_memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16);
+
+	/* jeff: set this becasue at least sw key is ready */
+	padapter->securitypriv.busetkipkey = _TRUE;
+
+	if (enqueue) {
+		ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+		if (ph2c == NULL) {
+			rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm));
+			res = _FAIL;
+			goto exit;
+		}
+
+		psetstakey_rsp = (struct set_stakey_rsp *)rtw_zmalloc(sizeof(struct set_stakey_rsp));
+		if (psetstakey_rsp == NULL) {
+			rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj));
+			rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm));
+			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);
+		res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	} else {
+		set_stakey_hdl(padapter, (u8 *)psetstakey_para);
+		rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm));
+	}
+exit:
+
+	return res;
+}
+
+u8 rtw_clearstakey_cmd(_adapter *padapter, struct sta_info *sta, 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 mlme_priv			*pmlmepriv = &padapter->mlmepriv;
+	struct security_priv		*psecuritypriv = &padapter->securitypriv;
+	s16 cam_id = 0;
+	u8	res = _SUCCESS;
+
+	if (!enqueue) {
+		while ((cam_id = rtw_camid_search(padapter, sta->hwaddr, -1, -1)) >= 0) {
+			RTW_PRINT("clear key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(sta->hwaddr), cam_id);
+			clear_cam_entry(padapter, cam_id);
+			rtw_camid_free(padapter, cam_id);
+		}
+	} else {
+		ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+		if (ph2c == NULL) {
+			res = _FAIL;
+			goto exit;
+		}
+
+		psetstakey_para = (struct set_stakey_parm *)rtw_zmalloc(sizeof(struct set_stakey_parm));
+		if (psetstakey_para == NULL) {
+			rtw_mfree((u8 *) ph2c, sizeof(struct	cmd_obj));
+			res = _FAIL;
+			goto exit;
+		}
+
+		psetstakey_rsp = (struct set_stakey_rsp *)rtw_zmalloc(sizeof(struct set_stakey_rsp));
+		if (psetstakey_rsp == NULL) {
+			rtw_mfree((u8 *) ph2c, sizeof(struct	cmd_obj));
+			rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm));
+			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);
+
+		_rtw_memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
+
+		psetstakey_para->algorithm = _NO_PRIVACY_;
+
+		res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+	}
+
+exit:
+
+	return res;
+}
+
+u8 rtw_addbareq_cmd(_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 = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	paddbareq_parm = (struct addBaReq_parm *)rtw_zmalloc(sizeof(struct addBaReq_parm));
+	if (paddbareq_parm == NULL) {
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct	cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	paddbareq_parm->tid = tid;
+	_rtw_memcpy(paddbareq_parm->addr, addr, ETH_ALEN);
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq));
+
+	/* RTW_INFO("rtw_addbareq_cmd, tid=%d\n", tid); */
+
+	/* rtw_enqueue_cmd(pcmdpriv, ph2c);	 */
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+	return res;
+}
+
+u8 rtw_addbarsp_cmd(_adapter *padapter, u8 *addr, u16 tid, u8 status, u8 size, u16 start_seq)
+{
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	struct cmd_obj *ph2c;
+	struct addBaRsp_parm *paddBaRsp_parm;
+	u8 res = _SUCCESS;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	paddBaRsp_parm = (struct addBaRsp_parm *)rtw_zmalloc(sizeof(struct addBaRsp_parm));
+
+	if (paddBaRsp_parm == NULL) {
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	_rtw_memcpy(paddBaRsp_parm->addr, addr, ETH_ALEN);
+	paddBaRsp_parm->tid = tid;
+	paddBaRsp_parm->status = status;
+	paddBaRsp_parm->size = size;
+	paddBaRsp_parm->start_seq = start_seq;
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, paddBaRsp_parm, GEN_CMD_CODE(_AddBARsp));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+	return res;
+}
+/* add for CONFIG_IEEE80211W, none 11w can use it */
+u8 rtw_reset_securitypriv_cmd(_adapter *padapter)
+{
+	struct cmd_obj		*ph2c;
+	struct drvextra_cmd_parm  *pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	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) {
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = RESET_SECURITYPRIV;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size = 0;
+	pdrvextra_cmd_parm->pbuf = NULL;
+
+	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_free_assoc_resources_cmd(_adapter *padapter)
+{
+	struct cmd_obj		*ph2c;
+	struct drvextra_cmd_parm  *pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	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) {
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = FREE_ASSOC_RESOURCES;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size = 0;
+	pdrvextra_cmd_parm->pbuf = NULL;
+
+	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_dynamic_chk_wk_cmd(_adapter *padapter)
+{
+	struct cmd_obj		*ph2c;
+	struct drvextra_cmd_parm  *pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	/* only  primary padapter does this cmd */
+
+	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) {
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size = 0;
+	pdrvextra_cmd_parm->pbuf = NULL;
+	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(_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;
+
+	RTW_INFO(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 = (struct set_ch_parm *)rtw_zmalloc(sizeof(*set_ch_parm));
+	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 = (struct cmd_obj *)rtw_zmalloc(sizeof(struct	cmd_obj));
+		if (pcmdobj == NULL) {
+			rtw_mfree((u8 *)set_ch_parm, sizeof(*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;
+
+		rtw_mfree((u8 *)set_ch_parm, sizeof(*set_ch_parm));
+	}
+
+	/* do something based on res... */
+
+exit:
+
+	RTW_INFO(FUNC_NDEV_FMT" res:%u\n", FUNC_NDEV_ARG(padapter->pnetdev), res);
+
+	return res;
+}
+
+u8 _rtw_set_chplan_cmd(_adapter *adapter, int flags, u8 chplan, const struct country_chplan *country_ent, u8 swconfig)
+{
+	struct cmd_obj *cmdobj;
+	struct	SetChannelPlan_param *parm;
+	struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
+	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	struct submit_ctx sctx;
+	u8 res = _SUCCESS;
+
+	/* check if allow software config */
+	if (swconfig && rtw_hal_is_disable_sw_channel_plan(adapter) == _TRUE) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	/* if country_entry is provided, replace chplan */
+	if (country_ent)
+		chplan = country_ent->chplan;
+
+	/* check input parameter */
+	if (!rtw_is_channel_plan_valid(chplan)) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	/* prepare cmd parameter */
+	parm = (struct SetChannelPlan_param *)rtw_zmalloc(sizeof(*parm));
+	if (parm == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	parm->country_ent = country_ent;
+	parm->channel_plan = chplan;
+
+	if (flags & RTW_CMDF_DIRECTLY) {
+		/* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+		if (H2C_SUCCESS != set_chplan_hdl(adapter, (u8 *)parm))
+			res = _FAIL;
+		rtw_mfree((u8 *)parm, sizeof(*parm));
+	} else {
+		/* need enqueue, prepare cmd_obj and enqueue */
+		cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj));
+		if (cmdobj == NULL) {
+			res = _FAIL;
+			rtw_mfree((u8 *)parm, sizeof(*parm));
+			goto exit;
+		}
+
+		init_h2fwcmd_w_parm_no_rsp(cmdobj, parm, GEN_CMD_CODE(_SetChannelPlan));
+
+		if (flags & RTW_CMDF_WAIT_ACK) {
+			cmdobj->sctx = &sctx;
+			rtw_sctx_init(&sctx, 2000);
+		}
+
+		res = rtw_enqueue_cmd(pcmdpriv, cmdobj);
+
+		if (res == _SUCCESS && (flags & RTW_CMDF_WAIT_ACK)) {
+			rtw_sctx_wait(&sctx, __func__);
+			_enter_critical_mutex(&pcmdpriv->sctx_mutex, NULL);
+			if (sctx.status == RTW_SCTX_SUBMITTED)
+				cmdobj->sctx = NULL;
+			_exit_critical_mutex(&pcmdpriv->sctx_mutex, NULL);
+		}
+	}
+
+exit:
+
+	return res;
+}
+
+inline u8 rtw_set_chplan_cmd(_adapter *adapter, int flags, u8 chplan, u8 swconfig)
+{
+	return _rtw_set_chplan_cmd(adapter, flags, chplan, NULL, swconfig);
+}
+
+inline u8 rtw_set_country_cmd(_adapter *adapter, int flags, const char *country_code, u8 swconfig)
+{
+	const struct country_chplan *ent;
+
+	if (is_alpha(country_code[0]) == _FALSE
+	    || is_alpha(country_code[1]) == _FALSE
+	   ) {
+		RTW_PRINT("%s input country_code is not alpha2\n", __func__);
+		return _FAIL;
+	}
+
+	ent = rtw_get_chplan_from_country(country_code);
+
+	if (ent == NULL) {
+		RTW_PRINT("%s unsupported country_code:\"%c%c\"\n", __func__, country_code[0], country_code[1]);
+		return _FAIL;
+	}
+
+	RTW_PRINT("%s country_code:\"%c%c\" mapping to chplan:0x%02x\n", __func__, country_code[0], country_code[1], ent->chplan);
+
+	return _rtw_set_chplan_cmd(adapter, flags, RTW_CHPLAN_MAX, ent, swconfig);
+}
+
+u8 rtw_enable_hw_update_tsf_cmd(_adapter *padapter)
+{
+	struct cmd_obj *ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	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) {
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = EN_HW_UPDATE_TSF_WK_CID;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->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;
+}
+
+/* from_timer == 1 means driver is in LPS */
+u8 traffic_status_watchdog(_adapter *padapter, u8 from_timer)
+{
+	u8	bEnterPS = _FALSE;
+	u16 BusyThresholdHigh;
+	u16	BusyThresholdLow;
+	u16	BusyThreshold;
+	u8	bBusyTraffic = _FALSE, bTxBusyTraffic = _FALSE, bRxBusyTraffic = _FALSE;
+	u8	bHigherBusyTraffic = _FALSE, bHigherBusyRxTraffic = _FALSE, bHigherBusyTxTraffic = _FALSE;
+
+	struct mlme_priv		*pmlmepriv = &(padapter->mlmepriv);
+
+	RT_LINK_DETECT_T *link_detect = &pmlmepriv->LinkDetectInfo;
+
+	if (padapter->registrypriv.wifi_spec != 1) {
+		BusyThresholdHigh = 25;
+		BusyThresholdLow = 10;
+	} else
+	{
+		BusyThresholdHigh = 100;
+		BusyThresholdLow = 75;
+	}
+	BusyThreshold = BusyThresholdHigh;
+
+	/*  */
+	/* Determine if our traffic is busy now */
+	/*  */
+	if ((check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
+	    /*&& !MgntInitAdapterInProgress(pMgntInfo)*/) {
+		/* if we raise bBusyTraffic in last watchdog, using lower threshold. */
+		if (pmlmepriv->LinkDetectInfo.bBusyTraffic)
+			BusyThreshold = BusyThresholdLow;
+
+		if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > BusyThreshold ||
+		    pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > BusyThreshold) {
+			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;
+		}
+
+#define TX_ACTIVE_TH 10
+#define RX_ACTIVE_TH 20
+#define TRAFFIC_PROTECT_PERIOD_MS 4500
+
+		if (link_detect->NumTxOkInPeriod > TX_ACTIVE_TH
+		    || link_detect->NumRxUnicastOkInPeriod > RX_ACTIVE_TH) {
+
+			RTW_INFO(FUNC_ADPT_FMT" acqiure wake_lock for %u ms(tx:%d,rx_unicast:%d)\n",
+				 FUNC_ADPT_ARG(padapter),
+				 TRAFFIC_PROTECT_PERIOD_MS,
+				 link_detect->NumTxOkInPeriod,
+				 link_detect->NumRxUnicastOkInPeriod);
+
+			rtw_lock_traffic_suspend_timeout(TRAFFIC_PROTECT_PERIOD_MS);
+		}
+
+		/* check traffic for  powersaving. */
+		if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) ||
+		    (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 4)
+		   ) {
+			bEnterPS = _FALSE;
+
+		} else {
+			bEnterPS = _TRUE;
+		}
+
+
+		/* LeisurePS only work in infra mode. */
+		if (bEnterPS) {
+			if (!from_timer) {
+				LPS_Enter(padapter, "TRAFFIC_IDLE");
+			} else {
+				/* do this at caller */
+				/* rtw_lps_ctrl_wk_cmd(adapter, LPS_CTRL_ENTER, 1); */
+				/* rtw_hal_dm_watchdog_in_lps(padapter); */
+			}
+		} else {
+			if (!from_timer)
+				LPS_Leave(padapter, "TRAFFIC_BUSY");
+			else {
+					rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_TRAFFIC_BUSY, 1);
+			}
+		}
+
+	} else {
+		struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+		int n_assoc_iface = 0;
+		int i;
+
+		for (i = 0; i < dvobj->iface_nums; i++) {
+			if (check_fwstate(&(dvobj->padapters[i]->mlmepriv), WIFI_ASOC_STATE))
+				n_assoc_iface++;
+		}
+
+		if (!from_timer && n_assoc_iface == 0)
+			LPS_Leave(padapter, "NON_LINKED");
+	}
+
+	session_tracker_chk_cmd(padapter, NULL);
+
+
+	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;
+
+	return bEnterPS;
+
+}
+
+/* for 11n Logo 4.2.31/4.2.32 */
+static void dynamic_update_bcn_check(_adapter *padapter)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+	if (!padapter->registrypriv.wifi_spec)
+		return;
+
+	if (!MLME_IS_AP(padapter))
+		return;
+
+	if (pmlmeext->bstart_bss) {
+		/* In 10 * 2 = 20s, there are no legacy AP, update HT info  */
+		static u8 count = 1;
+
+		if (count % 10 == 0) {
+			count = 1;
+
+			if (_FALSE == ATOMIC_READ(&pmlmepriv->olbc)
+				&& _FALSE == ATOMIC_READ(&pmlmepriv->olbc_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);
+				}
+			}
+		}
+
+		/* In 2s, there are any legacy AP, update HT info, and then reset count  */
+
+		if (_FALSE != ATOMIC_READ(&pmlmepriv->olbc)
+			&& _FALSE != ATOMIC_READ(&pmlmepriv->olbc_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);
+
+			}
+			ATOMIC_SET(&pmlmepriv->olbc, _FALSE);
+			ATOMIC_SET(&pmlmepriv->olbc_ht, _FALSE);
+			count = 0;
+		}
+
+		count ++;
+	}
+}
+void rtw_iface_dynamic_chk_wk_hdl(_adapter *padapter)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE)
+		expire_timeout_chk(padapter);
+	dynamic_update_bcn_check(padapter);
+
+	linked_status_chk(padapter, 0);
+	traffic_status_watchdog(padapter, 0);
+
+	/* for debug purpose */
+	_linked_info_dump(padapter);
+
+
+}
+void rtw_dynamic_chk_wk_hdl(_adapter *padapter)
+{
+	rtw_mi_dynamic_chk_wk_hdl(padapter);
+
+	rtw_hal_sreset_xmit_status_check(padapter);
+	rtw_hal_sreset_linked_status_check(padapter);
+
+	/* if(check_fwstate(pmlmepriv, _FW_UNDER_LINKING|_FW_UNDER_SURVEY)==_FALSE) */
+	{
+		dm_DynamicUsbTxAgg(padapter, 0);
+	}
+	rtw_hal_dm_watchdog(padapter);
+
+	/* check_hw_pbc(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type); */
+
+	/* BT-Coexist */
+	rtw_btcoex_Handler(padapter);
+
+#ifdef CONFIG_IPS_CHECK_IN_WD
+	/* always call rtw_ps_processor() at last one. */
+	rtw_ps_processor(padapter);
+#endif
+
+}
+
+
+void lps_ctrl_wk_hdl(_adapter *padapter, u8 lps_ctrl_type);
+void lps_ctrl_wk_hdl(_adapter *padapter, u8 lps_ctrl_type)
+{
+	struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+	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:
+		/* RTW_INFO("LPS_CTRL_SCAN\n"); */
+		rtw_btcoex_ScanNotify(padapter, _TRUE);
+		if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) {
+			/* connect */
+			LPS_Leave(padapter, "LPS_CTRL_SCAN");
+		}
+		break;
+	case LPS_CTRL_JOINBSS:
+		/* RTW_INFO("LPS_CTRL_JOINBSS\n"); */
+		LPS_Leave(padapter, "LPS_CTRL_JOINBSS");
+		break;
+	case LPS_CTRL_CONNECT:
+		/* RTW_INFO("LPS_CTRL_CONNECT\n"); */
+		mstatus = 1;/* connect */
+		/* Reset LPS Setting */
+		pwrpriv->LpsIdleCount = 0;
+		rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
+		rtw_btcoex_MediaStatusNotify(padapter, mstatus);
+		break;
+	case LPS_CTRL_DISCONNECT:
+		/* RTW_INFO("LPS_CTRL_DISCONNECT\n"); */
+		mstatus = 0;/* disconnect */
+		rtw_btcoex_MediaStatusNotify(padapter, mstatus);
+		LPS_Leave(padapter, "LPS_CTRL_DISCONNECT");
+		rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
+		break;
+	case LPS_CTRL_SPECIAL_PACKET:
+		/* RTW_INFO("LPS_CTRL_SPECIAL_PACKET\n"); */
+		pwrpriv->DelayLPSLastTimeStamp = rtw_get_current_time();
+		rtw_btcoex_SpecialPacketNotify(padapter, PACKET_DHCP);
+		LPS_Leave(padapter, "LPS_CTRL_SPECIAL_PACKET");
+		break;
+	case LPS_CTRL_LEAVE:
+		LPS_Leave(padapter, "LPS_CTRL_LEAVE");
+		break;
+	case LPS_CTRL_LEAVE_CFG80211_PWRMGMT:
+		LPS_Leave(padapter, "CFG80211_PWRMGMT");
+		break;
+	case LPS_CTRL_TRAFFIC_BUSY:
+		LPS_Leave(padapter, "LPS_CTRL_TRAFFIC_BUSY");
+		break;
+	case LPS_CTRL_TX_TRAFFIC_LEAVE:
+		LPS_Leave(padapter, "LPS_CTRL_TX_TRAFFIC_LEAVE");
+		break;
+	case LPS_CTRL_RX_TRAFFIC_LEAVE:
+		LPS_Leave(padapter, "LPS_CTRL_RX_TRAFFIC_LEAVE");
+		break;
+	case LPS_CTRL_ENTER:
+		LPS_Enter(padapter, "TRAFFIC_IDLE_1");
+		break;
+	default:
+		break;
+	}
+
+}
+
+u8 rtw_lps_ctrl_wk_cmd(_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 = adapter_to_pwrctl(padapter); */
+	u8	res = _SUCCESS;
+
+	/* if(!pwrctrlpriv->bLeisurePs) */
+	/*	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) {
+			rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+			res = _FAIL;
+			goto exit;
+		}
+
+		pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID;
+		pdrvextra_cmd_parm->type = lps_ctrl_type;
+		pdrvextra_cmd_parm->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);
+	} else
+		lps_ctrl_wk_hdl(padapter, lps_ctrl_type);
+
+exit:
+
+	return res;
+
+}
+
+void rtw_dm_in_lps_hdl(_adapter *padapter)
+{
+	rtw_hal_set_hwreg(padapter, HW_VAR_DM_IN_LPS, NULL);
+}
+
+void rtw_lps_change_dtim_hdl(_adapter *padapter, u8 dtim)
+{
+	struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+
+	if (dtim <= 0 || dtim > 16)
+		return;
+
+	if (rtw_btcoex_IsBtControlLps(padapter) == _TRUE)
+		return;
+
+
+	if (pwrpriv->dtim != dtim) {
+		RTW_INFO("change DTIM from %d to %d, bFwCurrentInPSMode=%d, ps_mode=%d\n", pwrpriv->dtim, dtim,
+			 pwrpriv->bFwCurrentInPSMode, pwrpriv->pwr_mode);
+
+		pwrpriv->dtim = dtim;
+	}
+
+	if ((pwrpriv->bFwCurrentInPSMode == _TRUE) && (pwrpriv->pwr_mode > PS_MODE_ACTIVE)) {
+		u8 ps_mode = pwrpriv->pwr_mode;
+
+		/* RTW_INFO("change DTIM from %d to %d, ps_mode=%d\n", pwrpriv->dtim, dtim, ps_mode); */
+
+		rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
+	}
+
+
+}
+
+
+u8 rtw_lps_change_dtim_cmd(_adapter *padapter, u8 dtim)
+{
+	struct cmd_obj	*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+	{
+		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) {
+			rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+			res = _FAIL;
+			goto exit;
+		}
+
+		pdrvextra_cmd_parm->ec_id = LPS_CHANGE_DTIM_CID;
+		pdrvextra_cmd_parm->type = dtim;
+		pdrvextra_cmd_parm->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;
+
+}
+
+
+
+void rtw_dm_ra_mask_hdl(_adapter *padapter, struct sta_info *psta)
+{
+	if (psta)
+		set_sta_rate(padapter, psta);
+}
+
+u8 rtw_dm_ra_mask_wk_cmd(_adapter *padapter, u8 *psta)
+{
+	struct cmd_obj	*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	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) {
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = DM_RA_MSK_WK_CID;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size = 0;
+	pdrvextra_cmd_parm->pbuf = psta;
+
+	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;
+
+}
+
+void power_saving_wk_hdl(_adapter *padapter)
+{
+	rtw_ps_processor(padapter);
+}
+
+/* add for CONFIG_IEEE80211W, none 11w can use it */
+void reset_securitypriv_hdl(_adapter *padapter)
+{
+	rtw_reset_securitypriv(padapter);
+}
+
+void free_assoc_resources_hdl(_adapter *padapter)
+{
+	rtw_free_assoc_resources(padapter, 1);
+}
+
+u8 p2p_protocol_wk_cmd(_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 = (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) {
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = P2P_PROTO_WK_CID;
+	pdrvextra_cmd_parm->type = intCmdType;	/*	As the command tppe. */
+	pdrvextra_cmd_parm->size = 0;
+	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;
+
+}
+
+
+u8 rtw_ps_cmd(_adapter *padapter)
+{
+	struct cmd_obj		*ppscmd;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+
+	u8	res = _SUCCESS;
+
+
+	ppscmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ppscmd == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (pdrvextra_cmd_parm == NULL) {
+		rtw_mfree((unsigned char *)ppscmd, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size = 0;
+	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;
+
+}
+
+
+static void rtw_chk_hi_queue_hdl(_adapter *padapter)
+{
+	struct sta_info *psta_bmc;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u32 start = rtw_get_current_time();
+	u8 empty = _FALSE;
+
+	psta_bmc = rtw_get_bcmc_stainfo(padapter);
+	if (!psta_bmc)
+		return;
+
+	rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty);
+
+	while (_FALSE == empty && rtw_get_passing_time_ms(start) < rtw_get_wait_hiq_empty_ms()) {
+		rtw_msleep_os(100);
+		rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty);
+	}
+
+	if (psta_bmc->sleepq_len == 0) {
+		if (empty == _SUCCESS) {
+			bool update_tim = _FALSE;
+
+			if (pstapriv->tim_bitmap & BIT(0))
+				update_tim = _TRUE;
+
+			pstapriv->tim_bitmap &= ~BIT(0);
+			pstapriv->sta_dz_bitmap &= ~BIT(0);
+
+			if (update_tim == _TRUE)
+				_update_beacon(padapter, _TIM_IE_, NULL, _TRUE, "bmc sleepq and HIQ empty");
+		} else /* re check again */
+			rtw_chk_hi_queue_cmd(padapter);
+
+	}
+
+}
+
+u8 rtw_chk_hi_queue_cmd(_adapter *padapter)
+{
+	struct cmd_obj	*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	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) {
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->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;
+
+}
+
+
+
+struct btinfo {
+	u8 cid;
+	u8 len;
+
+	u8 bConnection:1;
+	u8 bSCOeSCO:1;
+	u8 bInQPage:1;
+	u8 bACLBusy:1;
+	u8 bSCOBusy:1;
+	u8 bHID:1;
+	u8 bA2DP:1;
+	u8 bFTP:1;
+
+	u8 retry_cnt:4;
+	u8 rsvd_34:1;
+	u8 rsvd_35:1;
+	u8 rsvd_36:1;
+	u8 rsvd_37:1;
+
+	u8 rssi;
+
+	u8 rsvd_50:1;
+	u8 rsvd_51:1;
+	u8 rsvd_52:1;
+	u8 rsvd_53:1;
+	u8 rsvd_54:1;
+	u8 rsvd_55:1;
+	u8 eSCO_SCO:1;
+	u8 Master_Slave:1;
+
+	u8 rsvd_6;
+	u8 rsvd_7;
+};
+
+void btinfo_evt_dump(void *sel, void *buf)
+{
+	struct btinfo *info = (struct btinfo *)buf;
+
+	RTW_PRINT_SEL(sel, "cid:0x%02x, len:%u\n", info->cid, info->len);
+
+	if (info->len > 2)
+		RTW_PRINT_SEL(sel, "byte2:%s%s%s%s%s%s%s%s\n"
+			      , info->bConnection ? "bConnection " : ""
+			      , info->bSCOeSCO ? "bSCOeSCO " : ""
+			      , info->bInQPage ? "bInQPage " : ""
+			      , info->bACLBusy ? "bACLBusy " : ""
+			      , info->bSCOBusy ? "bSCOBusy " : ""
+			      , info->bHID ? "bHID " : ""
+			      , info->bA2DP ? "bA2DP " : ""
+			      , info->bFTP ? "bFTP" : ""
+			     );
+
+	if (info->len > 3)
+		RTW_PRINT_SEL(sel, "retry_cnt:%u\n", info->retry_cnt);
+
+	if (info->len > 4)
+		RTW_PRINT_SEL(sel, "rssi:%u\n", info->rssi);
+
+	if (info->len > 5)
+		RTW_PRINT_SEL(sel, "byte5:%s%s\n"
+			      , info->eSCO_SCO ? "eSCO_SCO " : ""
+			      , info->Master_Slave ? "Master_Slave " : ""
+			     );
+}
+
+static void rtw_btinfo_hdl(_adapter *adapter, u8 *buf, u16 buf_len)
+{
+#define BTINFO_WIFI_FETCH 0x23
+#define BTINFO_BT_AUTO_RPT 0x27
+	struct btinfo *info = (struct btinfo *)buf;
+	u8 cmd_idx;
+	u8 len;
+
+	cmd_idx = info->cid;
+
+	if (info->len > buf_len - 2) {
+		rtw_warn_on(1);
+		len = buf_len - 2;
+	} else
+		len = info->len;
+
+	/* #define DBG_PROC_SET_BTINFO_EVT */
+#ifdef DBG_PROC_SET_BTINFO_EVT
+	btinfo_evt_dump(RTW_DBGDUMP, info);
+#endif /* DBG_PROC_SET_BTINFO_EVT */
+
+	/* transform BT-FW btinfo to WiFI-FW C2H format and notify */
+	if (cmd_idx == BTINFO_WIFI_FETCH)
+		buf[1] = 0;
+	else if (cmd_idx == BTINFO_BT_AUTO_RPT)
+		buf[1] = 2;
+	rtw_btcoex_BtInfoNotify(adapter , len + 1, &buf[1]);
+}
+
+u8 rtw_test_h2c_cmd(_adapter *adapter, u8 *buf, u8 len)
+{
+	struct cmd_obj *pcmdobj;
+	struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+	u8 *ph2c_content;
+	struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (pcmdobj == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (pdrvextra_cmd_parm == NULL) {
+		rtw_mfree((u8 *)pcmdobj, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	ph2c_content = rtw_zmalloc(len);
+	if (ph2c_content == NULL) {
+		rtw_mfree((u8 *)pcmdobj, sizeof(struct cmd_obj));
+		rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = TEST_H2C_CID;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size = len;
+	pdrvextra_cmd_parm->pbuf = ph2c_content;
+
+	_rtw_memcpy(ph2c_content, buf, len);
+
+	init_h2fwcmd_w_parm_no_rsp(pcmdobj, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+
+exit:
+	return res;
+}
+
+static s32 rtw_mp_cmd_hdl(_adapter *padapter, u8 mp_cmd_id)
+{
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+	int ret = H2C_SUCCESS;
+	u8 rfreg0;
+
+	if (mp_cmd_id == MP_START) {
+		if (padapter->registrypriv.mp_mode == 0) {
+			rtw_hal_deinit(padapter);
+			padapter->registrypriv.mp_mode = 1;
+			rtw_hal_init(padapter);
+			MPT_InitializeAdapter(padapter, 1);
+		}
+
+		if (padapter->registrypriv.mp_mode == 0) {
+			ret = H2C_REJECTED;
+			goto exit;
+		}
+
+		if (padapter->mppriv.mode == MP_OFF) {
+			if (mp_start_test(padapter) == _FAIL) {
+				ret = H2C_REJECTED;
+				goto exit;
+			}
+			padapter->mppriv.mode = MP_ON;
+			MPT_PwrCtlDM(padapter, 0);
+		}
+		padapter->mppriv.bmac_filter = _FALSE;
+		odm_write_dig(&pHalData->odmpriv, 0x20);
+
+	} else if (mp_cmd_id == MP_STOP) {
+		if (padapter->registrypriv.mp_mode == 1) {
+			MPT_DeInitAdapter(padapter);
+			rtw_hal_deinit(padapter);
+			padapter->registrypriv.mp_mode = 0;
+			rtw_hal_init(padapter);
+		}
+
+		if (padapter->mppriv.mode != MP_OFF) {
+			mp_stop_test(padapter);
+			padapter->mppriv.mode = MP_OFF;
+		}
+
+	} else {
+		RTW_INFO(FUNC_ADPT_FMT"invalid id:%d\n", FUNC_ADPT_ARG(padapter), mp_cmd_id);
+		ret = H2C_PARAMETERS_ERROR;
+		rtw_warn_on(1);
+	}
+
+exit:
+	return ret;
+}
+
+u8 rtw_mp_cmd(_adapter *adapter, u8 mp_cmd_id, u8 flags)
+{
+	struct cmd_obj *cmdobj;
+	struct drvextra_cmd_parm *parm;
+	struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
+	struct submit_ctx sctx;
+	u8	res = _SUCCESS;
+
+	parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (parm == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	parm->ec_id = MP_CMD_WK_CID;
+	parm->type = mp_cmd_id;
+	parm->size = 0;
+	parm->pbuf = NULL;
+
+	if (flags & RTW_CMDF_DIRECTLY) {
+		/* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+		if (H2C_SUCCESS != rtw_mp_cmd_hdl(adapter, mp_cmd_id))
+			res = _FAIL;
+		rtw_mfree((u8 *)parm, sizeof(*parm));
+	} else {
+		/* need enqueue, prepare cmd_obj and enqueue */
+		cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj));
+		if (cmdobj == NULL) {
+			res = _FAIL;
+			rtw_mfree((u8 *)parm, sizeof(*parm));
+			goto exit;
+		}
+
+		init_h2fwcmd_w_parm_no_rsp(cmdobj, parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+		if (flags & RTW_CMDF_WAIT_ACK) {
+			cmdobj->sctx = &sctx;
+			rtw_sctx_init(&sctx, 10 * 1000);
+		}
+
+		res = rtw_enqueue_cmd(pcmdpriv, cmdobj);
+
+		if (res == _SUCCESS && (flags & RTW_CMDF_WAIT_ACK)) {
+			rtw_sctx_wait(&sctx, __func__);
+			_enter_critical_mutex(&pcmdpriv->sctx_mutex, NULL);
+			if (sctx.status == RTW_SCTX_SUBMITTED)
+				cmdobj->sctx = NULL;
+			_exit_critical_mutex(&pcmdpriv->sctx_mutex, NULL);
+			if (sctx.status != RTW_SCTX_DONE_SUCCESS)
+				res = _FAIL;
+		}
+	}
+
+exit:
+	return res;
+}
+
+u8 rtw_c2h_wk_cmd(PADAPTER padapter, u8 *pbuf, u16 length, u8 type)
+{
+	struct cmd_obj *ph2c;
+	struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	u8 *extra_cmd_buf;
+	u8 res = _SUCCESS;
+
+	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) {
+		rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	extra_cmd_buf = rtw_zmalloc(length);
+	if (extra_cmd_buf == NULL) {
+		rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj));
+		rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm));
+		res = _FAIL;
+		goto exit;
+	}
+
+	_rtw_memcpy(extra_cmd_buf, pbuf, length);
+	pdrvextra_cmd_parm->ec_id = C2H_WK_CID;
+	pdrvextra_cmd_parm->type = type;
+	pdrvextra_cmd_parm->size = length;
+	pdrvextra_cmd_parm->pbuf = extra_cmd_buf;
+
+	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;
+}
+
+
+inline u8 rtw_c2h_packet_wk_cmd(_adapter *adapter, u8 *c2h_evt, u16 length)
+{
+	return rtw_c2h_wk_cmd(adapter, c2h_evt, length, C2H_TYPE_PKT);
+}
+
+u8 rtw_run_in_thread_cmd(PADAPTER padapter, void (*func)(void *), void *context)
+{
+	struct cmd_priv *pcmdpriv;
+	struct cmd_obj *ph2c;
+	struct RunInThread_param *parm;
+	s32 res = _SUCCESS;
+
+	pcmdpriv = &padapter->cmdpriv;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (NULL == ph2c) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	parm = (struct RunInThread_param *)rtw_zmalloc(sizeof(struct RunInThread_param));
+	if (NULL == parm) {
+		rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	parm->func = func;
+	parm->context = context;
+	init_h2fwcmd_w_parm_no_rsp(ph2c, parm, GEN_CMD_CODE(_RunInThreadCMD));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+	return res;
+}
+
+u8 session_tracker_cmd(_adapter *adapter, u8 cmd, struct sta_info *sta, u8 *local_naddr, u8 *local_port, u8 *remote_naddr, u8 *remote_port)
+{
+	struct cmd_priv	*cmdpriv = &adapter->cmdpriv;
+	struct cmd_obj *cmdobj;
+	struct drvextra_cmd_parm *cmd_parm;
+	struct st_cmd_parm *st_parm;
+	u8	res = _SUCCESS;
+
+	cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (cmdobj == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (cmd_parm == NULL) {
+		rtw_mfree((u8 *)cmdobj, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	st_parm = (struct st_cmd_parm *)rtw_zmalloc(sizeof(struct st_cmd_parm));
+	if (st_parm == NULL) {
+		rtw_mfree((u8 *)cmdobj, sizeof(struct cmd_obj));
+		rtw_mfree((u8 *)cmd_parm, sizeof(struct drvextra_cmd_parm));
+		res = _FAIL;
+		goto exit;
+	}
+
+	st_parm->cmd = cmd;
+	st_parm->sta = sta;
+	if (cmd != ST_CMD_CHK) {
+		_rtw_memcpy(&st_parm->local_naddr, local_naddr, 4);
+		_rtw_memcpy(&st_parm->local_port, local_port, 2);
+		_rtw_memcpy(&st_parm->remote_naddr, remote_naddr, 4);
+		_rtw_memcpy(&st_parm->remote_port, remote_port, 2);
+	}
+
+	cmd_parm->ec_id = SESSION_TRACKER_WK_CID;
+	cmd_parm->type = 0;
+	cmd_parm->size = sizeof(struct st_cmd_parm);
+	cmd_parm->pbuf = (u8 *)st_parm;
+	init_h2fwcmd_w_parm_no_rsp(cmdobj, cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+	cmdobj->no_io = 1;
+
+	res = rtw_enqueue_cmd(cmdpriv, cmdobj);
+
+exit:
+	return res;
+}
+
+inline u8 session_tracker_chk_cmd(_adapter *adapter, struct sta_info *sta)
+{
+	return session_tracker_cmd(adapter, ST_CMD_CHK, sta, NULL, NULL, NULL, NULL);
+}
+
+inline u8 session_tracker_add_cmd(_adapter *adapter, struct sta_info *sta, u8 *local_naddr, u8 *local_port, u8 *remote_naddr, u8 *remote_port)
+{
+	return session_tracker_cmd(adapter, ST_CMD_ADD, sta, local_naddr, local_port, remote_naddr, remote_port);
+}
+
+inline u8 session_tracker_del_cmd(_adapter *adapter, struct sta_info *sta, u8 *local_naddr, u8 *local_port, u8 *remote_naddr, u8 *remote_port)
+{
+	return session_tracker_cmd(adapter, ST_CMD_DEL, sta, local_naddr, local_port, remote_naddr, remote_port);
+}
+
+void session_tracker_chk_for_sta(_adapter *adapter, struct sta_info *sta)
+{
+	struct st_ctl_t *st_ctl = &sta->st_ctl;
+	int i;
+	_irqL irqL;
+	_list *plist, *phead, *pnext;
+	_list dlist;
+	struct session_tracker *st = NULL;
+	u8 op_wfd_mode = MIRACAST_DISABLED;
+
+	if (DBG_SESSION_TRACKER)
+		RTW_INFO(FUNC_ADPT_FMT" sta:%p\n", FUNC_ADPT_ARG(adapter), sta);
+
+	if (!(sta->state & _FW_LINKED))
+		goto exit;
+
+	for (i = 0; i < SESSION_TRACKER_REG_ID_NUM; i++) {
+		if (st_ctl->reg[i].s_proto != 0)
+			break;
+	}
+	if (i >= SESSION_TRACKER_REG_ID_NUM)
+		goto chk_sta;
+
+	_rtw_init_listhead(&dlist);
+
+	_enter_critical_bh(&st_ctl->tracker_q.lock, &irqL);
+
+	phead = &st_ctl->tracker_q.queue;
+	plist = get_next(phead);
+	pnext = get_next(plist);
+	while (rtw_end_of_queue_search(phead, plist) == _FALSE) {
+		st = LIST_CONTAINOR(plist, struct session_tracker, list);
+		plist = pnext;
+		pnext = get_next(pnext);
+
+		if (st->status != ST_STATUS_ESTABLISH
+			&& rtw_get_passing_time_ms(st->set_time) > ST_EXPIRE_MS
+		) {
+			rtw_list_delete(&st->list);
+			rtw_list_insert_tail(&st->list, &dlist);
+		}
+
+		/* TODO: check OS for status update */
+		if (st->status == ST_STATUS_CHECK)
+			st->status = ST_STATUS_ESTABLISH;
+
+		if (st->status != ST_STATUS_ESTABLISH)
+			continue;
+
+		if (0)
+			RTW_INFO(FUNC_ADPT_FMT" local:%u, remote:%u, rtsp:%u, %u, %u\n", FUNC_ADPT_ARG(adapter)
+				, ntohs(st->local_port), ntohs(st->remote_port), adapter->wfd_info.rtsp_ctrlport, adapter->wfd_info.tdls_rtsp_ctrlport
+				, adapter->wfd_info.peer_rtsp_ctrlport);
+		if (ntohs(st->local_port) == adapter->wfd_info.rtsp_ctrlport)
+			op_wfd_mode |= MIRACAST_SINK;
+		if (ntohs(st->local_port) == adapter->wfd_info.tdls_rtsp_ctrlport)
+			op_wfd_mode |= MIRACAST_SINK;
+		if (ntohs(st->remote_port) == adapter->wfd_info.peer_rtsp_ctrlport)
+			op_wfd_mode |= MIRACAST_SOURCE;
+	}
+
+	_exit_critical_bh(&st_ctl->tracker_q.lock, &irqL);
+
+	plist = get_next(&dlist);
+	while (rtw_end_of_queue_search(&dlist, plist) == _FALSE) {
+		st = LIST_CONTAINOR(plist, struct session_tracker, list);
+		plist = get_next(plist);
+		rtw_mfree((u8 *)st, sizeof(struct session_tracker));
+	}
+
+chk_sta:
+	if (STA_OP_WFD_MODE(sta) != op_wfd_mode) {
+		STA_SET_OP_WFD_MODE(sta, op_wfd_mode);
+		rtw_sta_media_status_rpt_cmd(adapter, sta, 1);
+	}
+
+exit:
+	return;
+}
+
+void session_tracker_chk_for_adapter(_adapter *adapter)
+{
+	struct sta_priv *stapriv = &adapter->stapriv;
+	struct sta_info *sta;
+	int i;
+	_irqL irqL;
+	_list *plist, *phead;
+	u8 op_wfd_mode = MIRACAST_DISABLED;
+
+	_enter_critical_bh(&stapriv->sta_hash_lock, &irqL);
+
+	for (i = 0; i < NUM_STA; i++) {
+		phead = &(stapriv->sta_hash[i]);
+		plist = get_next(phead);
+
+		while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+			sta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+			plist = get_next(plist);
+
+			session_tracker_chk_for_sta(adapter, sta);
+
+			op_wfd_mode |= STA_OP_WFD_MODE(sta);
+		}
+	}
+
+	_exit_critical_bh(&stapriv->sta_hash_lock, &irqL);
+
+	adapter->wfd_info.op_wfd_mode = MIRACAST_MODE_REVERSE(op_wfd_mode);
+}
+
+void session_tracker_cmd_hdl(_adapter *adapter, struct st_cmd_parm *parm)
+{
+	u8 cmd = parm->cmd;
+	struct sta_info *sta = parm->sta;
+
+	if (cmd == ST_CMD_CHK) {
+		if (sta)
+			session_tracker_chk_for_sta(adapter, sta);
+		else
+			session_tracker_chk_for_adapter(adapter);
+
+		goto exit;
+
+	} else if (cmd == ST_CMD_ADD || cmd == ST_CMD_DEL) {
+		struct st_ctl_t *st_ctl;
+		u32 local_naddr = parm->local_naddr;
+		u16 local_port = parm->local_port;
+		u32 remote_naddr = parm->remote_naddr;
+		u16 remote_port = parm->remote_port;
+		struct session_tracker *st = NULL;
+		_irqL irqL;
+		_list *plist, *phead;
+		u8 free_st = 0;
+		u8 alloc_st = 0;
+
+		if (DBG_SESSION_TRACKER)
+			RTW_INFO(FUNC_ADPT_FMT" cmd:%u, sta:%p, local:"IP_FMT":"PORT_FMT", remote:"IP_FMT":"PORT_FMT"\n"
+				, FUNC_ADPT_ARG(adapter), cmd, sta
+				, IP_ARG(&local_naddr), PORT_ARG(&local_port)
+				, IP_ARG(&remote_naddr), PORT_ARG(&remote_port)
+			);
+
+		if (!(sta->state & _FW_LINKED))
+			goto exit;
+
+		st_ctl = &sta->st_ctl;
+
+		_enter_critical_bh(&st_ctl->tracker_q.lock, &irqL);
+
+		phead = &st_ctl->tracker_q.queue;
+		plist = get_next(phead);
+		while (rtw_end_of_queue_search(phead, plist) == _FALSE) {
+			st = LIST_CONTAINOR(plist, struct session_tracker, list);
+
+			if (st->local_naddr == local_naddr
+				&& st->local_port == local_port
+				&& st->remote_naddr == remote_naddr
+				&& st->remote_port == remote_port)
+				break;
+
+			plist = get_next(plist);
+		}
+
+		if (rtw_end_of_queue_search(phead, plist) == _TRUE)
+			st = NULL;
+
+		switch (cmd) {
+		case ST_CMD_DEL:
+			if (st) {
+				rtw_list_delete(plist);
+				free_st = 1;
+			}
+			goto unlock;
+		case ST_CMD_ADD:
+			if (!st)
+				alloc_st = 1;
+		}
+
+unlock:
+		_exit_critical_bh(&st_ctl->tracker_q.lock, &irqL);
+
+		if (free_st) {
+			rtw_mfree((u8 *)st, sizeof(struct session_tracker));
+			goto exit;
+		}
+
+		if (alloc_st) {
+			st = (struct session_tracker *)rtw_zmalloc(sizeof(struct session_tracker));
+			if (!st)
+				goto exit;
+
+			st->local_naddr = local_naddr;
+			st->local_port = local_port;
+			st->remote_naddr = remote_naddr;
+			st->remote_port = remote_port;
+			st->set_time = rtw_get_current_time();
+			st->status = ST_STATUS_CHECK;
+
+			_enter_critical_bh(&st_ctl->tracker_q.lock, &irqL);
+			rtw_list_insert_tail(&st->list, phead);
+			_exit_critical_bh(&st_ctl->tracker_q.lock, &irqL);
+		}
+	}
+
+exit:
+	return;
+}
+
+u8 rtw_drvextra_cmd_hdl(_adapter *padapter, unsigned char *pbuf)
+{
+	int ret = H2C_SUCCESS;
+	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 STA_MSTATUS_RPT_WK_CID:
+		rtw_sta_media_status_rpt_cmd_hdl(padapter, (struct sta_media_status_rpt_cmd_parm *)pdrvextra_cmd->pbuf);
+		break;
+
+	case DYNAMIC_CHK_WK_CID:/*only  primary padapter go to this cmd, but execute dynamic_chk_wk_hdl() for two interfaces */
+		rtw_dynamic_chk_wk_hdl(padapter);
+		break;
+	case POWER_SAVING_CTRL_WK_CID:
+		power_saving_wk_hdl(padapter);
+		break;
+	case LPS_CTRL_WK_CID:
+		lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type);
+		break;
+	case DM_IN_LPS_WK_CID:
+		rtw_dm_in_lps_hdl(padapter);
+		break;
+	case LPS_CHANGE_DTIM_CID:
+		rtw_lps_change_dtim_hdl(padapter, (u8)pdrvextra_cmd->type);
+		break;
+	case P2P_PS_WK_CID:
+		p2p_ps_wk_hdl(padapter, pdrvextra_cmd->type);
+		break;
+	case P2P_PROTO_WK_CID:
+		/*
+		* Commented by Albert 2011/07/01
+		* I used the type_size as the type command
+		*/
+		ret = p2p_protocol_wk_hdl(padapter, pdrvextra_cmd->type, pdrvextra_cmd->pbuf);
+		break;
+	case CHECK_HIQ_WK_CID:
+		rtw_chk_hi_queue_hdl(padapter);
+		break;
+	/* add for CONFIG_IEEE80211W, none 11w can use it */
+	case RESET_SECURITYPRIV:
+		reset_securitypriv_hdl(padapter);
+		break;
+	case FREE_ASSOC_RESOURCES:
+		free_assoc_resources_hdl(padapter);
+		break;
+	case C2H_WK_CID:
+		switch (pdrvextra_cmd->type) {
+		case C2H_TYPE_PKT:
+			rtw_hal_c2h_pkt_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->size);
+			break;
+		default:
+			RTW_ERR("unknown C2H type:%d\n", pdrvextra_cmd->type);
+			rtw_warn_on(1);
+			break;
+		}
+		break;
+	case DM_RA_MSK_WK_CID:
+		rtw_dm_ra_mask_hdl(padapter, (struct sta_info *)pdrvextra_cmd->pbuf);
+		break;
+	case BTINFO_WK_CID:
+		rtw_btinfo_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->size);
+		break;
+	case SESSION_TRACKER_WK_CID:
+		session_tracker_cmd_hdl(padapter, (struct st_cmd_parm *)pdrvextra_cmd->pbuf);
+		break;
+	case EN_HW_UPDATE_TSF_WK_CID:
+		rtw_hal_set_hwreg(padapter, HW_VAR_EN_HW_UPDATE_TSF, NULL);
+		break;
+	case TEST_H2C_CID:
+		rtw_hal_fill_h2c_cmd(padapter, pdrvextra_cmd->pbuf[0], pdrvextra_cmd->size - 1, &pdrvextra_cmd->pbuf[1]);
+		break;
+	case MP_CMD_WK_CID:
+		ret = rtw_mp_cmd_hdl(padapter, pdrvextra_cmd->type);
+		break;
+	default:
+		break;
+	}
+
+	if (pdrvextra_cmd->pbuf && pdrvextra_cmd->size > 0)
+		rtw_mfree(pdrvextra_cmd->pbuf, pdrvextra_cmd->size);
+
+	return ret;
+}
+
+void rtw_survey_cmd_callback(_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 */
+		mlme_set_scan_to_timer(pmlmepriv, 1);
+	} else if (pcmd->res != H2C_SUCCESS) {
+		mlme_set_scan_to_timer(pmlmepriv, 1);
+	}
+
+	/* free cmd */
+	rtw_free_cmd_obj(pcmd);
+
+}
+void rtw_disassoc_cmd_callback(_adapter	*padapter,  struct cmd_obj *pcmd)
+{
+	_irqL	irqL;
+	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+	if (pcmd->res != H2C_SUCCESS) {
+		_enter_critical_bh(&pmlmepriv->lock, &irqL);
+		set_fwstate(pmlmepriv, _FW_LINKED);
+		_exit_critical_bh(&pmlmepriv->lock, &irqL);
+		goto exit;
+	}
+	else /* clear bridge database */
+		nat25_db_cleanup(padapter);
+
+	/* free cmd */
+	rtw_free_cmd_obj(pcmd);
+
+exit:
+	return;
+}
+
+void rtw_getmacreg_cmdrsp_callback(_adapter *padapter,  struct cmd_obj *pcmd)
+{
+
+	rtw_free_cmd_obj(pcmd);
+
+}
+
+void rtw_joinbss_cmd_callback(_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)
+		_set_timer(&pmlmepriv->assoc_timer, 1);
+
+	rtw_free_cmd_obj(pcmd);
+
+}
+
+void rtw_create_ibss_post_hdl(_adapter *padapter, int status)
+{
+	_irqL irqL;
+	struct sta_info *psta = NULL;
+	struct wlan_network *pwlan = NULL;
+	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	WLAN_BSSID_EX *pdev_network = &padapter->registrypriv.dev_network;
+	struct wlan_network *mlme_cur_network = &(pmlmepriv->cur_network);
+
+	if (status != H2C_SUCCESS)
+		_set_timer(&pmlmepriv->assoc_timer, 1);
+
+	_cancel_timer_ex(&pmlmepriv->assoc_timer);
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	{
+		_irqL irqL;
+
+		pwlan = _rtw_alloc_network(pmlmepriv);
+		_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+		if (pwlan == NULL) {
+			pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue);
+			if (pwlan == NULL) {
+				_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+				goto createbss_cmd_fail;
+			}
+			pwlan->last_scanned = rtw_get_current_time();
+		} else
+			rtw_list_insert_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue);
+
+		pdev_network->Length = get_WLAN_BSSID_EX_sz(pdev_network);
+		_rtw_memcpy(&(pwlan->network), pdev_network, pdev_network->Length);
+		/* pwlan->fixed = _TRUE; */
+
+		/* copy pdev_network information to pmlmepriv->cur_network */
+		_rtw_memcpy(&mlme_cur_network->network, pdev_network, (get_WLAN_BSSID_EX_sz(pdev_network)));
+
+		_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+		_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+		/* we will set _FW_LINKED when there is one more sat to join us (rtw_stassoc_event_callback) */
+	}
+
+createbss_cmd_fail:
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+	return;
+}
+
+void rtw_setstaKey_cmdrsp_callback(_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) {
+		goto exit;
+	}
+
+	/* psta->aid = psta->mac_id = psetstakey_rsp->keyid; */ /* CAM_ID(CAM_ENTRY) */
+
+exit:
+
+	rtw_free_cmd_obj(pcmd);
+
+}
+void rtw_setassocsta_cmdrsp_callback(_adapter	*padapter,  struct cmd_obj *pcmd)
+{
+	_irqL	irqL;
+	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) {
+		goto exit;
+	}
+
+	psta->aid = psta->mac_id = passocsta_rsp->cam_id;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	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);
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+exit:
+	rtw_free_cmd_obj(pcmd);
+
+}
diff --git a/drivers/staging/rtl8821ce/core/rtw_debug.c b/drivers/staging/rtl8821ce/core/rtw_debug.c
new file mode 100644
index 000000000000..010920377bee
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/rtw_debug.c
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * 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 <drv_types.h>
+#include <hal_data.h>
+#include <rtw_version.h>
+
+void dump_drv_version(void *sel)
+{
+	RTW_PRINT_SEL(sel, "%s %s\n", DRV_NAME, DRIVERVERSION);
+}
+
+void mac_reg_dump(void *sel, _adapter *adapter)
+{
+	int i, j = 1;
+
+	RTW_PRINT_SEL(sel, "======= MAC REG =======\n");
+
+	for (i = 0x0; i < 0x800; i += 4) {
+		if (j % 4 == 1)
+			RTW_PRINT_SEL(sel, "0x%04x", i);
+		_RTW_PRINT_SEL(sel, " 0x%08x ", rtw_read32(adapter, i));
+		if ((j++) % 4 == 0)
+			_RTW_PRINT_SEL(sel, "\n");
+	}
+
+	for (i = 0x1000; i < 0x1800; i += 4) {
+		if (j % 4 == 1)
+			RTW_PRINT_SEL(sel, "0x%04x", i);
+		_RTW_PRINT_SEL(sel, " 0x%08x ", rtw_read32(adapter, i));
+		if ((j++) % 4 == 0)
+			_RTW_PRINT_SEL(sel, "\n");
+	}
+}
+
+void bb_reg_dump(void *sel, _adapter *adapter)
+{
+	int i, j = 1;
+
+	RTW_PRINT_SEL(sel, "======= BB REG =======\n");
+	for (i = 0x800; i < 0x1000; i += 4) {
+		if (j % 4 == 1)
+			RTW_PRINT_SEL(sel, "0x%04x", i);
+		_RTW_PRINT_SEL(sel, " 0x%08x ", rtw_read32(adapter, i));
+		if ((j++) % 4 == 0)
+			_RTW_PRINT_SEL(sel, "\n");
+	}
+
+	for (i = 0x1800; i < 0x2000; i += 4) {
+		if (j % 4 == 1)
+			RTW_PRINT_SEL(sel, "0x%04x", i);
+		_RTW_PRINT_SEL(sel, " 0x%08x ", rtw_read32(adapter, i));
+		if ((j++) % 4 == 0)
+			_RTW_PRINT_SEL(sel, "\n");
+	}
+}
+
+void bb_reg_dump_ex(void *sel, _adapter *adapter)
+{
+	int i, j = 1;
+
+	RTW_PRINT_SEL(sel, "======= BB REG =======\n");
+	for (i = 0x800; i < 0x1000; i += 4) {
+		RTW_PRINT_SEL(sel, "0x%04x", i);
+		_RTW_PRINT_SEL(sel, " 0x%08x ", rtw_read32(adapter, i));
+		_RTW_PRINT_SEL(sel, "\n");
+	}
+
+	for (i = 0x1800; i < 0x2000; i += 4) {
+		RTW_PRINT_SEL(sel, "0x%04x", i);
+		_RTW_PRINT_SEL(sel, " 0x%08x ", rtw_read32(adapter, i));
+		_RTW_PRINT_SEL(sel, "\n");
+	}
+}
+
+void rf_reg_dump(void *sel, _adapter *adapter)
+{
+	int i, j = 1, path;
+	u32 value;
+	u8 rf_type = 0;
+	u8 path_nums = 0;
+
+	rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+	if ((RF_1T2R == rf_type) || (RF_1T1R == rf_type))
+		path_nums = 1;
+	else
+		path_nums = 2;
+
+	RTW_PRINT_SEL(sel, "======= RF REG =======\n");
+
+	for (path = 0; path < path_nums; path++) {
+		RTW_PRINT_SEL(sel, "RF_Path(%x)\n", path);
+		for (i = 0; i < 0x100; i++) {
+			value = rtw_hal_read_rfreg(adapter, path, i, 0xffffffff);
+			if (j % 4 == 1)
+				RTW_PRINT_SEL(sel, "0x%02x ", i);
+			_RTW_PRINT_SEL(sel, " 0x%08x ", value);
+			if ((j++) % 4 == 0)
+				_RTW_PRINT_SEL(sel, "\n");
+		}
+	}
+}
+
+void rtw_sink_rtp_seq_dbg(_adapter *adapter, _pkt *pkt)
+{
+	struct recv_priv *precvpriv = &(adapter->recvpriv);
+	if (precvpriv->sink_udpport > 0) {
+		if (*((u16 *)((pkt->data) + 0x24)) == cpu_to_be16(precvpriv->sink_udpport)) {
+			precvpriv->pre_rtp_rxseq = precvpriv->cur_rtp_rxseq;
+			precvpriv->cur_rtp_rxseq = be16_to_cpu(*((u16 *)((pkt->data) + 0x2C)));
+			if (precvpriv->pre_rtp_rxseq + 1 != precvpriv->cur_rtp_rxseq)
+				RTW_INFO("%s : RTP Seq num from %d to %d\n", __FUNCTION__, precvpriv->pre_rtp_rxseq, precvpriv->cur_rtp_rxseq);
+		}
+	}
+}
+
+void sta_rx_reorder_ctl_dump(void *sel, struct sta_info *sta)
+{
+	struct recv_reorder_ctrl *reorder_ctl;
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		reorder_ctl = &sta->recvreorder_ctrl[i];
+		if (reorder_ctl->ampdu_size != RX_AMPDU_SIZE_INVALID || reorder_ctl->indicate_seq != 0xFFFF) {
+			RTW_PRINT_SEL(sel, "tid=%d, enable=%d, ampdu_size=%u, indicate_seq=%u\n"
+				, i, reorder_ctl->enable, reorder_ctl->ampdu_size, reorder_ctl->indicate_seq
+				     );
+		}
+	}
+}
+
+void dump_adapters_status(void *sel, struct dvobj_priv *dvobj)
+{
+	struct rf_ctl_t *rfctl = dvobj_to_rfctl(dvobj);
+	int i;
+	_adapter *iface;
+	u8 u_ch, u_bw, u_offset;
+
+	dump_mi_status(sel, dvobj);
+
+
+	RTW_PRINT_SEL(sel, "dev status:%s%s\n\n"
+		, dev_is_surprise_removed(dvobj) ? " SR" : ""
+		, dev_is_drv_stopped(dvobj) ? " DS" : ""
+	);
+
+#define P2P_INFO_TITLE_FMT	" %-3s %-4s"
+#define P2P_INFO_TITLE_ARG	, "lch", "p2ps"
+#define P2P_INFO_VALUE_FMT	" %3u %4u"
+#define P2P_INFO_VALUE_ARG	, iface->wdinfo.listen_channel, rtw_p2p_state(&iface->wdinfo)
+#define P2P_INFO_DASH		"---------"
+
+	RTW_PRINT_SEL(sel, "%-2s %-15s %c %-3s %-3s %-3s %-17s %-4s %-7s"
+		P2P_INFO_TITLE_FMT
+		" %s\n"
+		, "id", "ifname", ' ', "bup", "nup", "ncd", "macaddr", "port", "ch"
+		P2P_INFO_TITLE_ARG
+		, "status");
+
+	RTW_PRINT_SEL(sel, "---------------------------------------------------------------"
+		P2P_INFO_DASH
+		"-------\n");
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		iface = dvobj->padapters[i];
+		if (iface) {
+			RTW_PRINT_SEL(sel, "%2d %-15s %c %3u %3u %3u "MAC_FMT" %4hhu %3u,%u,%u"
+				P2P_INFO_VALUE_FMT
+				" "MLME_STATE_FMT"\n"
+				, i, iface->registered ? ADPT_ARG(iface) : NULL
+				, iface->registered ? 'R' : ' '
+				, iface->bup
+				, iface->netif_up
+				, iface->net_closed
+				, MAC_ARG(adapter_mac_addr(iface))
+				, get_hw_port(iface)
+				, iface->mlmeextpriv.cur_channel
+				, iface->mlmeextpriv.cur_bwmode
+				, iface->mlmeextpriv.cur_ch_offset
+				P2P_INFO_VALUE_ARG
+				, MLME_STATE_ARG(iface)
+			);
+		}
+	}
+
+	RTW_PRINT_SEL(sel, "---------------------------------------------------------------"
+		P2P_INFO_DASH
+		"-------\n");
+
+	rtw_mi_get_ch_setting_union(dvobj_get_primary_adapter(dvobj), &u_ch, &u_bw, &u_offset);
+	RTW_PRINT_SEL(sel, "%55s %3u,%u,%u\n"
+		, "union:"
+		, u_ch, u_bw, u_offset
+	);
+
+	RTW_PRINT_SEL(sel, "%55s %3u,%u,%u\n"
+		, "oper:"
+		, dvobj->oper_channel
+		, dvobj->oper_bwmode
+		, dvobj->oper_ch_offset
+	);
+
+}
+
+static u8 fwdl_test_chksum_fail = 0;
+static u8 fwdl_test_wintint_rdy_fail = 0;
+
+static u8 del_rx_ampdu_test_no_tx_fail = 0;
+
+bool rtw_del_rx_ampdu_test_trigger_no_tx_fail(void)
+{
+	if (del_rx_ampdu_test_no_tx_fail) {
+		RTW_PRINT("del_rx_ampdu test case: trigger no_tx_fail\n");
+		del_rx_ampdu_test_no_tx_fail--;
+		return _TRUE;
+	}
+	return _FALSE;
+}
+
+static u32 g_wait_hiq_empty_ms = 0;
+
+u32 rtw_get_wait_hiq_empty_ms(void)
+{
+	return g_wait_hiq_empty_ms;
+}
+
+static u32 sta_linking_test_start_time = 0;
+static u32 sta_linking_test_wait_ms = 0;
+static u8 sta_linking_test_force_fail = 0;
+
+void rtw_sta_linking_test_set_start(void)
+{
+	sta_linking_test_start_time = rtw_get_current_time();
+}
+
+bool rtw_sta_linking_test_wait_done(void)
+{
+	return rtw_get_passing_time_ms(sta_linking_test_start_time) >= sta_linking_test_wait_ms;
+}
+
+bool rtw_sta_linking_test_force_fail(void)
+{
+	return sta_linking_test_force_fail;
+}
+
diff --git a/drivers/staging/rtl8821ce/core/rtw_ieee80211.c b/drivers/staging/rtl8821ce/core/rtw_ieee80211.c
new file mode 100644
index 000000000000..1ff6a2b353a3
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/rtw_ieee80211.c
@@ -0,0 +1,2271 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * 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 <drv_types.h>
+
+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
+};
+
+u8 mgn_rates_cck[4] = {MGN_1M, MGN_2M, MGN_5_5M, MGN_11M};
+u8 mgn_rates_ofdm[8] = {MGN_6M, MGN_9M, MGN_12M, MGN_18M, MGN_24M, MGN_36M, MGN_48M, MGN_54M};
+u8 mgn_rates_mcs0_7[8] = {MGN_MCS0, MGN_MCS1, MGN_MCS2, MGN_MCS3, MGN_MCS4, MGN_MCS5, MGN_MCS6, MGN_MCS7};
+u8 mgn_rates_mcs8_15[8] = {MGN_MCS8, MGN_MCS9, MGN_MCS10, MGN_MCS11, MGN_MCS12, MGN_MCS13, MGN_MCS14, MGN_MCS15};
+u8 mgn_rates_mcs16_23[8] = {MGN_MCS16, MGN_MCS17, MGN_MCS18, MGN_MCS19, MGN_MCS20, MGN_MCS21, MGN_MCS22, MGN_MCS23};
+u8 mgn_rates_mcs24_31[8] = {MGN_MCS24, MGN_MCS25, MGN_MCS26, MGN_MCS27, MGN_MCS28, MGN_MCS29, MGN_MCS30, MGN_MCS31};
+u8 mgn_rates_vht1ss[10] = {MGN_VHT1SS_MCS0, MGN_VHT1SS_MCS1, MGN_VHT1SS_MCS2, MGN_VHT1SS_MCS3, MGN_VHT1SS_MCS4
+	, MGN_VHT1SS_MCS5, MGN_VHT1SS_MCS6, MGN_VHT1SS_MCS7, MGN_VHT1SS_MCS8, MGN_VHT1SS_MCS9
+			  };
+u8 mgn_rates_vht2ss[10] = {MGN_VHT2SS_MCS0, MGN_VHT2SS_MCS1, MGN_VHT2SS_MCS2, MGN_VHT2SS_MCS3, MGN_VHT2SS_MCS4
+	, MGN_VHT2SS_MCS5, MGN_VHT2SS_MCS6, MGN_VHT2SS_MCS7, MGN_VHT2SS_MCS8, MGN_VHT2SS_MCS9
+			  };
+u8 mgn_rates_vht3ss[10] = {MGN_VHT3SS_MCS0, MGN_VHT3SS_MCS1, MGN_VHT3SS_MCS2, MGN_VHT3SS_MCS3, MGN_VHT3SS_MCS4
+	, MGN_VHT3SS_MCS5, MGN_VHT3SS_MCS6, MGN_VHT3SS_MCS7, MGN_VHT3SS_MCS8, MGN_VHT3SS_MCS9
+			  };
+u8 mgn_rates_vht4ss[10] = {MGN_VHT4SS_MCS0, MGN_VHT4SS_MCS1, MGN_VHT4SS_MCS2, MGN_VHT4SS_MCS3, MGN_VHT4SS_MCS4
+	, MGN_VHT4SS_MCS5, MGN_VHT4SS_MCS6, MGN_VHT4SS_MCS7, MGN_VHT4SS_MCS8, MGN_VHT4SS_MCS9
+			  };
+
+static const char *const _rate_section_str[] = {
+	"CCK",
+	"OFDM",
+	"HT_1SS",
+	"HT_2SS",
+	"HT_3SS",
+	"HT_4SS",
+	"VHT_1SS",
+	"VHT_2SS",
+	"VHT_3SS",
+	"VHT_4SS",
+	"RATE_SECTION_UNKNOWN",
+};
+
+const char *rate_section_str(u8 section)
+{
+	section = (section >= RATE_SECTION_NUM) ? RATE_SECTION_NUM : section;
+	return _rate_section_str[section];
+}
+
+struct rate_section_ent rates_by_sections[RATE_SECTION_NUM] = {
+	{RF_1TX, 4, mgn_rates_cck},
+	{RF_1TX, 8, mgn_rates_ofdm},
+	{RF_1TX, 8, mgn_rates_mcs0_7},
+	{RF_2TX, 8, mgn_rates_mcs8_15},
+	{RF_3TX, 8, mgn_rates_mcs16_23},
+	{RF_4TX, 8, mgn_rates_mcs24_31},
+	{RF_1TX, 10, mgn_rates_vht1ss},
+	{RF_2TX, 10, mgn_rates_vht2ss},
+	{RF_3TX, 10, mgn_rates_vht3ss},
+	{RF_4TX, 10, mgn_rates_vht4ss},
+};
+
+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)
+{
+	_rtw_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,
+	sint index,
+	uint len,
+	u8 *source,
+	uint *frlen /* frame length */
+)
+{
+	*pbuf = (u8)index;
+
+	*(pbuf + 1) = (u8)len;
+
+	if (len > 0)
+		_rtw_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);
+}
+
+/*----------------------------------------------------------------------------
+index: the information element id index, limit is the limit for search
+-----------------------------------------------------------------------------*/
+u8 *rtw_get_ie(u8 *pbuf, sint index, sint *len, sint limit)
+{
+	sint 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;
+}
+
+void rtw_set_supported_rate(u8 *SupportedRates, uint mode)
+{
+
+	_rtw_memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX);
+
+	switch (mode) {
+	case WIRELESS_11B:
+		_rtw_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 ? */
+	case WIRELESS_11_5AC:
+		_rtw_memcpy(SupportedRates, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
+		break;
+
+	case WIRELESS_11BG:
+	case WIRELESS_11G_24N:
+	case WIRELESS_11_24N:
+	case WIRELESS_11BG_24N:
+		_rtw_memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
+		_rtw_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;
+	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 */
+	*(u16 *)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod); /* BCN_INTERVAL; */
+	sz += 2;
+	ie += 2;
+
+	/* capability info */
+	*(u16 *)ie = 0;
+
+	*(u16 *)ie |= cpu_to_le16(cap_IBSS);
+
+	if (pregistrypriv->preamble == PREAMBLE_SHORT)
+		*(u16 *)ie |= cpu_to_le16(cap_ShortPremble);
+
+	if (pdev_network->Privacy)
+		*(u16 *)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 if (pregistrypriv->wireless_mode == WIRELESS_MODE_MAX) { /* WIRELESS_11ABGN | WIRELESS_11AC */
+		if (pdev_network->Configuration.DSConfig > 14)
+			wireless_mode = WIRELESS_11_5AC;
+		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);
+
+	/* HT Cap. */
+	if (((pregistrypriv->wireless_mode & WIRELESS_11_5N) || (pregistrypriv->wireless_mode & WIRELESS_11_24N))
+	    && (pregistrypriv->ht_enable == _TRUE)) {
+		/* todo: */
+	}
+
+	/* pdev_network->IELength =  sz; */ /* update IELength */
+
+	/* return _SUCCESS; */
+
+	return sz;
+
+}
+
+unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit)
+{
+	int len;
+	u16 val16;
+	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 (_rtw_memcmp((pbuf + 2), wpa_oui_type, sizeof(wpa_oui_type)) == _FALSE)
+
+				goto check_next_ie;
+
+			/* check version... */
+			_rtw_memcpy((u8 *)&val16, (pbuf + 6), sizeof(val16));
+
+			val16 = le16_to_cpu(val16);
+			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 (_rtw_memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_NONE;
+	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_WEP40;
+	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_TKIP;
+	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_CCMP;
+	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_WEP104;
+
+	return 0;
+}
+
+int rtw_get_wpa2_cipher_suite(u8 *s)
+{
+	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_NONE;
+	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_WEP40;
+	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_TKIP;
+	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_CCMP;
+	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN) == _TRUE)
+		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)) ||
+	    (_rtw_memcmp(wpa_ie + 2, RTW_WPA_OUI_TYPE, WPA_SELECTOR_LEN) != _TRUE))
+		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) {
+
+		return _FAIL;
+	}
+
+	/* pairwise_cipher */
+	if (left >= 2) {
+		/* count = le16_to_cpu(*(u16*)pos);	 */
+		count = RTW_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+
+		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+			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) {
+		return _FAIL;
+	}
+
+	if (is_8021x) {
+		if (left >= 6) {
+			pos += 2;
+			if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) {
+				*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) {
+		return _FAIL;
+	}
+
+	/* pairwise_cipher */
+	if (left >= 2) {
+		/* count = le16_to_cpu(*(u16*)pos); */
+		count = RTW_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+
+		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+			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) {
+
+		return _FAIL;
+	}
+
+	if (is_8021x) {
+		if (left >= 6) {
+			pos += 2;
+			if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) {
+				*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_) && (_rtw_memcmp(&in_ie[cnt + 2], &wpa_oui[0], 4) == _TRUE)) {
+
+			if (wpa_ie)
+				_rtw_memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
+
+			*wpa_len = in_ie[cnt + 1] + 2;
+			cnt += in_ie[cnt + 1] + 2; /* get next */
+		} else {
+			if (authmode == _WPA2_IE_ID_) {
+
+				if (rsn_ie)
+					_rtw_memcpy(rsn_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
+
+				*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_) && (_rtw_memcmp(&ie_ptr[2], wps_oui, 4) == _TRUE)) {
+		/* RTW_INFO("==> found WPS_IE.....\n"); */
+		*wps_ielen = ie_ptr[1] + 2;
+		match = _TRUE;
+	}
+	return match;
+}
+
+u8 *rtw_get_wps_ie_from_scan_queue(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen, u8 frame_type)
+{
+	u8	*wps = NULL;
+
+	RTW_INFO("[%s] frame_type = %d\n", __FUNCTION__, frame_type);
+	switch (frame_type) {
+	case 1:
+	case 3: {
+		/*	Beacon or Probe Response */
+		wps = rtw_get_wps_ie(in_ie + _PROBERSP_IE_OFFSET_, in_len - _PROBERSP_IE_OFFSET_, wps_ie, wps_ielen);
+		break;
+	}
+	case 2: {
+		/*	Probe Request */
+		wps = rtw_get_wps_ie(in_ie + _PROBEREQ_IE_OFFSET_ , in_len - _PROBEREQ_IE_OFFSET_ , wps_ie, wps_ielen);
+		break;
+	}
+	}
+	return wps;
+}
+
+/**
+ * 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] = {0x00, 0x50, 0xf2, 0x04};
+
+	if (wps_ielen)
+		*wps_ielen = 0;
+
+	if (!in_ie) {
+		rtw_warn_on(1);
+		return wpsie_ptr;
+	}
+
+	if (in_len <= 0)
+		return wpsie_ptr;
+
+	cnt = 0;
+
+	while (cnt + 1 + 4 < in_len) {
+		eid = in_ie[cnt];
+
+		if (cnt + 1 + 4 >= MAX_IE_SZ) {
+			rtw_warn_on(1);
+			return NULL;
+		}
+
+		if (eid == WLAN_EID_VENDOR_SPECIFIC && _rtw_memcmp(&in_ie[cnt + 2], wps_oui, 4) == _TRUE) {
+			wpsie_ptr = in_ie + cnt;
+
+			if (wps_ie)
+				_rtw_memcpy(wps_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
+
+			if (wps_ielen)
+				*wps_ielen = in_ie[cnt + 1] + 2;
+
+			break;
+		} else
+			cnt += in_ie[cnt + 1] + 2;
+
+	}
+
+	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_) ||
+	    (_rtw_memcmp(wps_ie + 2, wps_oui , 4) != _TRUE))
+		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;
+
+		/* RTW_INFO("%s attr_ptr:%p, id:%u, length:%u\n", __FUNCTION__, attr_ptr, attr_id, attr_data_len); */
+		if (attr_id == target_attr_id) {
+			target_attr_ptr = attr_ptr;
+
+			if (buf_attr)
+				_rtw_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)
+			_rtw_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) {
+			RTW_INFO("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) {
+				RTW_DBG("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:
+				RTW_DBG("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:
+			RTW_DBG("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:
+			RTW_DBG("Unknown Broadcom "
+				"information element ignored "
+				"(type=%d len=%lu)\n",
+				pos[3], (unsigned long) elen);
+			return -1;
+		}
+		break;
+
+	default:
+		RTW_DBG("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
+ */
+ParseRes 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;
+
+	_rtw_memset(elems, 0, sizeof(*elems));
+
+	while (left >= 2) {
+		u8 id, elen;
+
+		id = *pos++;
+		elen = *pos++;
+		left -= 2;
+
+		if (elen > left) {
+			if (show_errors) {
+				RTW_INFO("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;
+		case WLAN_EID_VHT_CAPABILITY:
+			elems->vht_capabilities = pos;
+			elems->vht_capabilities_len = elen;
+			break;
+		case WLAN_EID_VHT_OPERATION:
+			elems->vht_operation = pos;
+			elems->vht_operation_len = elen;
+			break;
+		case WLAN_EID_VHT_OP_MODE_NOTIFY:
+			elems->vht_op_mode_notify = pos;
+			elems->vht_op_mode_notify_len = elen;
+			break;
+		default:
+			unknown++;
+			if (!show_errors)
+				break;
+			RTW_DBG("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;
+
+}
+
+static u8 key_char2num(u8 ch);
+static 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 key_2char2num(u8 hch, u8 lch);
+u8 key_2char2num(u8 hch, u8 lch)
+{
+	return (key_char2num(hch) << 4) | key_char2num(lch);
+}
+
+void macstr2num(u8 *dst, u8 *src);
+void macstr2num(u8 *dst, u8 *src)
+{
+	int	jj, kk;
+	for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+		dst[jj] = key_2char2num(src[kk], src[kk + 1]);
+}
+
+/*
+ * Description:
+ * rtw_check_invalid_mac_address:
+ * This is only used for checking mac address valid or not.
+ *
+ * Input:
+ * adapter: mac_address pointer.
+ * check_local_bit: check locally bit or not.
+ *
+ * Output:
+ * _TRUE: The mac address is invalid.
+ * _FALSE: The mac address is valid.
+ *
+ * Auther: Isaac.Li
+ */
+u8 rtw_check_invalid_mac_address(u8 *mac_addr, u8 check_local_bit)
+{
+	u8 null_mac_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
+	u8 multi_mac_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	u8 res = _FALSE;
+
+	if (_rtw_memcmp(mac_addr, null_mac_addr, ETH_ALEN)) {
+		res = _TRUE;
+		goto func_exit;
+	}
+
+	if (_rtw_memcmp(mac_addr, multi_mac_addr, ETH_ALEN)) {
+		res = _TRUE;
+		goto func_exit;
+	}
+
+	if (mac_addr[0] & BIT0) {
+		res = _TRUE;
+		goto func_exit;
+	}
+
+	if (check_local_bit == _TRUE) {
+		if (mac_addr[0] & BIT1) {
+			res = _TRUE;
+			goto func_exit;
+		}
+	}
+
+func_exit:
+	return res;
+}
+
+extern char *rtw_initmac;
+/**
+ * rtw_macaddr_cfg - Decide the mac address used
+ * @out: buf to store mac address decided
+ * @hw_mac_addr: mac address from efuse/epprom
+ */
+void rtw_macaddr_cfg(u8 *out, const u8 *hw_mac_addr)
+{
+#define DEFAULT_RANDOM_MACADDR 1
+	u8 mac[ETH_ALEN];
+
+	if (out == NULL) {
+		rtw_warn_on(1);
+		return;
+	}
+
+	/* Users specify the mac address */
+	if (rtw_initmac) {
+		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]);
+
+		goto err_chk;
+	}
+
+	/* platform specified */
+
+	/* Use the mac address stored in the Efuse */
+	if (hw_mac_addr) {
+		_rtw_memcpy(mac, hw_mac_addr, ETH_ALEN);
+		goto err_chk;
+	}
+
+err_chk:
+	if (rtw_check_invalid_mac_address(mac, _TRUE) == _TRUE) {
+		RTW_ERR("invalid mac addr:"MAC_FMT", assign random MAC\n", MAC_ARG(mac));
+		*((u32 *)(&mac[2])) = rtw_random32();
+		mac[0] = 0x00;
+		mac[1] = 0xe0;
+		mac[2] = 0x4c;
+	}
+
+	_rtw_memcpy(out, mac, ETH_ALEN);
+	RTW_INFO("%s mac addr:"MAC_FMT"\n", __func__, MAC_ARG(out));
+}
+
+void dump_ht_cap_ie_content(void *sel, u8 *buf, u32 buf_len)
+{
+	if (buf_len != 26) {
+		RTW_PRINT_SEL(sel, "Invalid HT capability IE len:%d != %d\n", buf_len, 26);
+		return;
+	}
+
+	RTW_PRINT_SEL(sel, "HT Capabilities Info:%02x%02x\n", *(buf), *(buf + 1));
+	RTW_PRINT_SEL(sel, "A-MPDU Parameters:"HT_AMPDU_PARA_FMT"\n"
+		      , HT_AMPDU_PARA_ARG(HT_CAP_ELE_AMPDU_PARA(buf)));
+	RTW_PRINT_SEL(sel, "Supported MCS Set:"HT_SUP_MCS_SET_FMT"\n"
+		      , HT_SUP_MCS_SET_ARG(HT_CAP_ELE_SUP_MCS_SET(buf)));
+}
+
+void dump_ht_cap_ie(void *sel, u8 *ie, u32 ie_len)
+{
+	u8 *pos = (u8 *)ie;
+	u16 id;
+	u16 len;
+
+	u8 *ht_cap_ie;
+	sint ht_cap_ielen;
+
+	ht_cap_ie = rtw_get_ie(ie, _HT_CAPABILITY_IE_, &ht_cap_ielen, ie_len);
+	if (!ie || ht_cap_ie != ie)
+		return;
+
+	dump_ht_cap_ie_content(sel, ht_cap_ie + 2, ht_cap_ielen);
+}
+
+void dump_ies(void *sel, u8 *buf, u32 buf_len)
+{
+	u8 *pos = (u8 *)buf;
+	u8 id, len;
+
+	while (pos - buf + 1 < buf_len) {
+		id = *pos;
+		len = *(pos + 1);
+
+		RTW_PRINT_SEL(sel, "%s ID:%u, LEN:%u\n", __FUNCTION__, id, len);
+		dump_ht_cap_ie(sel, pos, len + 2);
+		dump_wps_ie(sel, pos, len + 2);
+		dump_p2p_ie(sel, pos, len + 2);
+		dump_wfd_ie(sel, pos, len + 2);
+
+		pos += (2 + len);
+	}
+}
+
+void dump_wps_ie(void *sel, 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 + 4 <= ie_len) {
+		id = RTW_GET_BE16(pos);
+		len = RTW_GET_BE16(pos + 2);
+
+		RTW_PRINT_SEL(sel, "%s ID:0x%04x, LEN:%u%s\n", __func__, id, len
+			, ((pos - ie + 4 + len) <= ie_len) ? "" : "(exceed ie_len)");
+
+		pos += (4 + len);
+	}
+}
+
+/**
+ * rtw_ies_get_chbw - get operation ch, bw, offset from IEs of BSS.
+ * @ies: pointer of the first tlv IE
+ * @ies_len: length of @ies
+ * @ch: pointer of ch, used as output
+ * @bw: pointer of bw, used as output
+ * @offset: pointer of offset, used as output
+ */
+void rtw_ies_get_chbw(u8 *ies, int ies_len, u8 *ch, u8 *bw, u8 *offset)
+{
+	u8 *p;
+	int	ie_len;
+
+	*ch = 0;
+	*bw = CHANNEL_WIDTH_20;
+	*offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+	p = rtw_get_ie(ies, _DSSET_IE_, &ie_len, ies_len);
+	if (p && ie_len > 0)
+		*ch = *(p + 2);
+
+	{
+		u8 *ht_cap_ie, *ht_op_ie;
+		int ht_cap_ielen, ht_op_ielen;
+
+		ht_cap_ie = rtw_get_ie(ies, EID_HTCapability, &ht_cap_ielen, ies_len);
+		if (ht_cap_ie && ht_cap_ielen) {
+			if (GET_HT_CAP_ELE_CHL_WIDTH(ht_cap_ie + 2))
+				*bw = CHANNEL_WIDTH_40;
+		}
+
+		ht_op_ie = rtw_get_ie(ies, EID_HTInfo, &ht_op_ielen, ies_len);
+		if (ht_op_ie && ht_op_ielen) {
+			if (*ch == 0)
+				*ch = GET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2);
+			else if (*ch != 0 && *ch != GET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2)) {
+				RTW_INFO("%s ch inconsistent, DSSS:%u, HT primary:%u\n"
+					, __func__, *ch, GET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2));
+			}
+
+			if (!GET_HT_OP_ELE_STA_CHL_WIDTH(ht_op_ie + 2))
+				*bw = CHANNEL_WIDTH_20;
+
+			if (*bw == CHANNEL_WIDTH_40) {
+				switch (GET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2)) {
+				case SCA:
+					*offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+					break;
+				case SCB:
+					*offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+					break;
+				}
+			}
+		}
+	}
+	{
+		u8 *vht_op_ie;
+		int vht_op_ielen;
+
+		vht_op_ie = rtw_get_ie(ies, EID_VHTOperation, &vht_op_ielen, ies_len);
+		if (vht_op_ie && vht_op_ielen) {
+			/* enable VHT 80 before check enable HT40 or not */
+			if (GET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2)  >=  1) {
+				/* for HT40, enable VHT80 */
+				if (*bw == CHANNEL_WIDTH_40)
+					*bw = CHANNEL_WIDTH_80;
+				/* for HT20, enable VHT20 */
+				else if (*bw == CHANNEL_WIDTH_20) {
+					/* modify VHT OP IE */
+					SET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2, 0);
+					/* reset to 0 for VHT20 */
+					SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(vht_op_ie + 2, 0);
+					SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(vht_op_ie + 2, 0);
+				}
+			} else {
+				/*
+				  VHT OP WIDTH = 0  under HT20/HT40
+				  if REGSTY_BW_5G(pregistrypriv) < CHANNEL_WIDTH_80 in rtw_build_vht_operation_ie
+				*/
+			}
+		}
+	}
+}
+
+void rtw_bss_get_chbw(WLAN_BSSID_EX *bss, u8 *ch, u8 *bw, u8 *offset)
+{
+	rtw_ies_get_chbw(bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)
+		, bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)
+		, ch, bw, offset);
+
+	if (*ch == 0)
+		*ch = bss->Configuration.DSConfig;
+	else if (*ch != bss->Configuration.DSConfig) {
+		RTW_INFO("inconsistent ch - ies:%u bss->Configuration.DSConfig:%u\n"
+			 , *ch, bss->Configuration.DSConfig);
+		*ch = bss->Configuration.DSConfig;
+		rtw_warn_on(1);
+	}
+}
+
+/**
+ * rtw_is_chbw_grouped - test if the two ch settings can be grouped together
+ * @ch_a: ch of set a
+ * @bw_a: bw of set a
+ * @offset_a: offset of set a
+ * @ch_b: ch of set b
+ * @bw_b: bw of set b
+ * @offset_b: offset of set b
+ */
+bool rtw_is_chbw_grouped(u8 ch_a, u8 bw_a, u8 offset_a
+			 , u8 ch_b, u8 bw_b, u8 offset_b)
+{
+	bool is_grouped = _FALSE;
+
+	if (ch_a != ch_b) {
+		/* ch is different */
+		goto exit;
+	} else if ((bw_a == CHANNEL_WIDTH_40 || bw_a == CHANNEL_WIDTH_80)
+		   && (bw_b == CHANNEL_WIDTH_40 || bw_b == CHANNEL_WIDTH_80)
+		  ) {
+		if (offset_a != offset_b)
+			goto exit;
+	}
+
+	is_grouped = _TRUE;
+
+exit:
+	return is_grouped;
+}
+
+/**
+ * rtw_sync_chbw - obey g_ch, adjust g_bw, g_offset, bw, offset
+ * @req_ch: pointer of the request ch, may be modified further
+ * @req_bw: pointer of the request bw, may be modified further
+ * @req_offset: pointer of the request offset, may be modified further
+ * @g_ch: pointer of the ongoing group ch
+ * @g_bw: pointer of the ongoing group bw, may be modified further
+ * @g_offset: pointer of the ongoing group offset, may be modified further
+ */
+void rtw_sync_chbw(u8 *req_ch, u8 *req_bw, u8 *req_offset
+		   , u8 *g_ch, u8 *g_bw, u8 *g_offset)
+{
+
+	*req_ch = *g_ch;
+
+	if (*req_bw == CHANNEL_WIDTH_80 && *g_ch <= 14) {
+		/*2.4G ch, downgrade to 40Mhz */
+		*req_bw = CHANNEL_WIDTH_40;
+	}
+
+	switch (*req_bw) {
+	case CHANNEL_WIDTH_80:
+		if (*g_bw == CHANNEL_WIDTH_40 || *g_bw == CHANNEL_WIDTH_80)
+			*req_offset = *g_offset;
+		else if (*g_bw == CHANNEL_WIDTH_20)
+			*req_offset = rtw_get_offset_by_ch(*req_ch);
+
+		if (*req_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) {
+			RTW_ERR("%s req 80MHz BW without offset, down to 20MHz\n", __func__);
+			rtw_warn_on(1);
+			*req_bw = CHANNEL_WIDTH_20;
+		}
+		break;
+	case CHANNEL_WIDTH_40:
+		if (*g_bw == CHANNEL_WIDTH_40 || *g_bw == CHANNEL_WIDTH_80)
+			*req_offset = *g_offset;
+		else if (*g_bw == CHANNEL_WIDTH_20)
+			*req_offset = rtw_get_offset_by_ch(*req_ch);
+
+		if (*req_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) {
+			RTW_ERR("%s req 40MHz BW without offset, down to 20MHz\n", __func__);
+			rtw_warn_on(1);
+			*req_bw = CHANNEL_WIDTH_20;
+		}
+		break;
+	case CHANNEL_WIDTH_20:
+		*req_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+		break;
+	default:
+		RTW_ERR("%s req unsupported BW:%u\n", __func__, *req_bw);
+		rtw_warn_on(1);
+	}
+
+	if (*req_bw > *g_bw) {
+		*g_bw = *req_bw;
+		*g_offset = *req_offset;
+	}
+}
+
+/**
+ * rtw_get_p2p_merged_len - Get merged ie length from muitiple p2p ies.
+ * @in_ie: Pointer of the first p2p ie
+ * @in_len: Total len of muiltiple p2p ies
+ * Returns: Length of merged p2p ie length
+ */
+u32 rtw_get_p2p_merged_ies_len(u8 *in_ie, u32 in_len)
+{
+	PNDIS_802_11_VARIABLE_IEs	pIE;
+	u8 OUI[4] = { 0x50, 0x6f, 0x9a, 0x09 };
+	int i = 0;
+	int j = 0, len = 0;
+
+	while (i < in_len) {
+		pIE = (PNDIS_802_11_VARIABLE_IEs)(in_ie + i);
+
+		if (pIE->ElementID == _VENDOR_SPECIFIC_IE_ && _rtw_memcmp(pIE->data, OUI, 4)) {
+			len += pIE->Length - 4; /* 4 is P2P OUI length, don't count it in this loop */
+		}
+
+		i += (pIE->Length + 2);
+	}
+
+	return len + 4;	/* Append P2P OUI length at last. */
+}
+
+/**
+ * rtw_p2p_merge_ies - Merge muitiple p2p ies into one
+ * @in_ie: Pointer of the first p2p ie
+ * @in_len: Total len of muiltiple p2p ies
+ * @merge_ie: Pointer of merged ie
+ * Returns: Length of merged p2p ie
+ */
+int rtw_p2p_merge_ies(u8 *in_ie, u32 in_len, u8 *merge_ie)
+{
+	PNDIS_802_11_VARIABLE_IEs	pIE;
+	u8 len = 0;
+	u8 OUI[4] = { 0x50, 0x6f, 0x9a, 0x09 };
+	u8 ELOUI[6] = { 0xDD, 0x00, 0x50, 0x6f, 0x9a, 0x09 };	/* EID;Len;OUI, Len would copy at the end of function */
+	int i = 0;
+
+	if (merge_ie != NULL) {
+		/* Set first P2P OUI */
+		_rtw_memcpy(merge_ie, ELOUI, 6);
+		merge_ie += 6;
+
+		while (i < in_len) {
+			pIE = (PNDIS_802_11_VARIABLE_IEs)(in_ie + i);
+
+			/* Take out the rest of P2P OUIs */
+			if (pIE->ElementID == _VENDOR_SPECIFIC_IE_ && _rtw_memcmp(pIE->data, OUI, 4)) {
+				_rtw_memcpy(merge_ie, pIE->data + 4, pIE->Length - 4);
+				len += pIE->Length - 4;
+				merge_ie += pIE->Length - 4;
+			}
+
+			i += (pIE->Length + 2);
+		}
+
+		return len + 4;	/* 4 is for P2P OUI */
+
+	}
+
+	return 0;
+}
+
+void dump_p2p_ie(void *sel, 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 + 3 <= ie_len) {
+		id = *pos;
+		len = RTW_GET_LE16(pos + 1);
+
+		RTW_PRINT_SEL(sel, "%s ID:%u, LEN:%u%s\n", __func__, id, len
+			, ((pos - ie + 3 + len) <= ie_len) ? "" : "(exceed ie_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;
+	u8 *p2p_ie_ptr = NULL;
+	u8 eid, p2p_oui[4] = {0x50, 0x6F, 0x9A, 0x09};
+
+	if (p2p_ielen)
+		*p2p_ielen = 0;
+
+	if (!in_ie || in_len < 0) {
+		rtw_warn_on(1);
+		return p2p_ie_ptr;
+	}
+
+	if (in_len <= 0)
+		return p2p_ie_ptr;
+
+	cnt = 0;
+
+	while (cnt + 1 + 4 < in_len) {
+		eid = in_ie[cnt];
+
+		if (cnt + 1 + 4 >= MAX_IE_SZ) {
+			rtw_warn_on(1);
+			return NULL;
+		}
+
+		if (eid == WLAN_EID_VENDOR_SPECIFIC && _rtw_memcmp(&in_ie[cnt + 2], p2p_oui, 4) == _TRUE) {
+			p2p_ie_ptr = in_ie + cnt;
+
+			if (p2p_ie)
+				_rtw_memcpy(p2p_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
+
+			if (p2p_ielen)
+				*p2p_ielen = in_ie[cnt + 1] + 2;
+
+			break;
+		} else
+			cnt += in_ie[cnt + 1] + 2;
+
+	}
+
+	return p2p_ie_ptr;
+}
+
+/**
+ * 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_ielen <= 6
+	    || (p2p_ie[0] != WLAN_EID_VENDOR_SPECIFIC)
+	    || (_rtw_memcmp(p2p_ie + 2, p2p_oui, 4) != _TRUE))
+		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 + 3) <= p2p_ielen) {
+		/* 3 = 1(Attribute ID) + 2(Length) */
+		u8 attr_id = *attr_ptr;
+		u16 attr_data_len = RTW_GET_LE16(attr_ptr + 1);
+		u16 attr_len = attr_data_len + 3;
+
+		if (0)
+			RTW_INFO("%s attr_ptr:%p, id:%u, length:%u\n", __func__, attr_ptr, attr_id, attr_data_len);
+
+		if ((attr_ptr - p2p_ie + attr_len) > p2p_ielen)
+			break;
+
+		if (attr_id == target_attr_id) {
+			target_attr_ptr = attr_ptr;
+
+			if (buf_attr)
+				_rtw_memcpy(buf_attr, attr_ptr, attr_len);
+
+			if (len_attr)
+				*len_attr = attr_len;
+
+			break;
+		} else
+			attr_ptr += attr_len;
+	}
+
+	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)
+			_rtw_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)
+		_rtw_memcpy(pbuf + 3, pdata_attr, attr_len);
+
+	a_len = attr_len + 3;
+
+	return a_len;
+}
+
+uint rtw_del_p2p_attr(u8 *ie, uint ielen_ori, u8 attr_id)
+{
+#define DBG_DEL_P2P_ATTR 0
+
+	u8 *target_attr;
+	u32 target_attr_len;
+	uint ielen = ielen_ori;
+	int index = 0;
+
+	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);
+
+			if (DBG_DEL_P2P_ATTR) {
+				RTW_INFO("%s %d before\n", __func__, index);
+				dump_ies(RTW_DBGDUMP, ie, ielen);
+
+				RTW_INFO("ie:%p, ielen:%u\n", ie, ielen);
+				RTW_INFO("target_attr:%p, target_attr_len:%u\n", target_attr, target_attr_len);
+				RTW_INFO("next_attr:%p, remain_len:%u\n", next_attr, remain_len);
+			}
+
+			_rtw_memmove(target_attr, next_attr, remain_len);
+			_rtw_memset(target_attr + remain_len, 0, target_attr_len);
+			*(ie + 1) -= target_attr_len;
+			ielen -= target_attr_len;
+
+			if (DBG_DEL_P2P_ATTR) {
+				RTW_INFO("%s %d after\n", __func__, index);
+				dump_ies(RTW_DBGDUMP, ie, ielen);
+			}
+
+			index++;
+		} else
+			break;
+	}
+
+	return ielen;
+}
+
+inline u8 *rtw_bss_ex_get_p2p_ie(WLAN_BSSID_EX *bss_ex, u8 *p2p_ie, uint *p2p_ielen)
+{
+	return rtw_get_p2p_ie(BSS_EX_TLV_IES(bss_ex), BSS_EX_TLV_IES_LEN(bss_ex), p2p_ie, p2p_ielen);
+}
+
+void rtw_bss_ex_del_p2p_attr(WLAN_BSSID_EX *bss_ex, u8 attr_id)
+{
+#define DBG_BSS_EX_DEL_P2P_ATTR 0
+
+	u8 *ies = BSS_EX_TLV_IES(bss_ex);
+	uint ies_len = BSS_EX_TLV_IES_LEN(bss_ex);
+
+	u8 *ie;
+	uint ie_len, ie_len_ori;
+
+	int index = 0;
+
+	while (1) {
+		ie = rtw_get_p2p_ie(ies, ies_len, NULL, &ie_len_ori);
+		if (ie) {
+			u8 *next_ie_ori = ie + ie_len_ori;
+			uint remain_len = bss_ex->IELength - (next_ie_ori - bss_ex->IEs);
+			u8 has_target_attr = 0;
+
+			if (DBG_BSS_EX_DEL_P2P_ATTR) {
+				if (rtw_get_p2p_attr(ie, ie_len_ori, attr_id, NULL, NULL)) {
+					RTW_INFO("%s %d before\n", __func__, index);
+					dump_ies(RTW_DBGDUMP, BSS_EX_TLV_IES(bss_ex), BSS_EX_TLV_IES_LEN(bss_ex));
+
+					RTW_INFO("ies:%p, ies_len:%u\n", ies, ies_len);
+					RTW_INFO("ie:%p, ie_len_ori:%u\n", ie, ie_len_ori);
+					RTW_INFO("next_ie_ori:%p, remain_len:%u\n", next_ie_ori, remain_len);
+					has_target_attr = 1;
+				}
+			}
+
+			ie_len = rtw_del_p2p_attr(ie, ie_len_ori, attr_id);
+			if (ie_len != ie_len_ori) {
+				u8 *next_ie = ie + ie_len;
+
+				_rtw_memmove(next_ie, next_ie_ori, remain_len);
+				_rtw_memset(next_ie + remain_len, 0, ie_len_ori - ie_len);
+				bss_ex->IELength -= ie_len_ori - ie_len;
+
+				ies = next_ie;
+			} else
+				ies = next_ie_ori;
+
+			if (DBG_BSS_EX_DEL_P2P_ATTR) {
+				if (has_target_attr) {
+					RTW_INFO("%s %d after\n", __func__, index);
+					dump_ies(RTW_DBGDUMP, BSS_EX_TLV_IES(bss_ex), BSS_EX_TLV_IES_LEN(bss_ex));
+				}
+			}
+
+			ies_len = remain_len;
+
+			index++;
+		} else
+			break;
+	}
+}
+
+void dump_wfd_ie(void *sel, u8 *ie, u32 ie_len)
+{
+	u8 *pos = (u8 *)ie;
+	u8 id;
+	u16 len;
+
+	u8 *wfd_ie;
+	uint wfd_ielen;
+
+	wfd_ie = rtw_get_wfd_ie(ie, ie_len, NULL, &wfd_ielen);
+	if (wfd_ie != ie || wfd_ielen == 0)
+		return;
+
+	pos += 6;
+	while (pos - ie + 3 <= ie_len) {
+		id = *pos;
+		len = RTW_GET_BE16(pos + 1);
+
+		RTW_PRINT_SEL(sel, "%s ID:%u, LEN:%u%s\n", __func__, id, len
+			, ((pos - ie + 3 + len) <= ie_len) ? "" : "(exceed ie_len)");
+
+		pos += (3 + len);
+	}
+}
+
+/**
+ * rtw_get_wfd_ie - Search WFD IE from a series of IEs
+ * @in_ie: Address of IEs to search
+ * @in_len: Length limit from in_ie
+ * @wfd_ie: If not NULL and WFD IE is found, WFD IE will be copied to the buf starting from wfd_ie
+ * @wfd_ielen: If not NULL and WFD IE is found, will set to the length of the entire WFD IE
+ *
+ * Returns: The address of the P2P IE found, or NULL
+ */
+u8 *rtw_get_wfd_ie(u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen)
+{
+	uint cnt;
+	u8 *wfd_ie_ptr = NULL;
+	u8 eid, wfd_oui[4] = {0x50, 0x6F, 0x9A, 0x0A};
+
+	if (wfd_ielen)
+		*wfd_ielen = 0;
+
+	if (!in_ie || in_len < 0) {
+		rtw_warn_on(1);
+		return wfd_ie_ptr;
+	}
+
+	if (in_len <= 0)
+		return wfd_ie_ptr;
+
+	cnt = 0;
+
+	while (cnt + 1 + 4 < in_len) {
+		eid = in_ie[cnt];
+
+		if (cnt + 1 + 4 >= MAX_IE_SZ) {
+			rtw_warn_on(1);
+			return NULL;
+		}
+
+		if (eid == WLAN_EID_VENDOR_SPECIFIC && _rtw_memcmp(&in_ie[cnt + 2], wfd_oui, 4) == _TRUE) {
+			wfd_ie_ptr = in_ie + cnt;
+
+			if (wfd_ie)
+				_rtw_memcpy(wfd_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
+
+			if (wfd_ielen)
+				*wfd_ielen = in_ie[cnt + 1] + 2;
+
+			break;
+		} else
+			cnt += in_ie[cnt + 1] + 2;
+
+	}
+
+	return wfd_ie_ptr;
+}
+
+/**
+ * rtw_get_wfd_attr - Search a specific WFD attribute from a given WFD IE
+ * @wfd_ie: Address of WFD IE to search
+ * @wfd_ielen: Length limit from wfd_ie
+ * @target_attr_id: The attribute ID of WFD attribute to search
+ * @buf_attr: If not NULL and the WFD attribute is found, WFD attribute will be copied to the buf starting from buf_attr
+ * @len_attr: If not NULL and the WFD attribute is found, will set to the length of the entire WFD attribute
+ *
+ * Returns: the address of the specific WPS attribute found, or NULL
+ */
+u8 *rtw_get_wfd_attr(u8 *wfd_ie, uint wfd_ielen, u8 target_attr_id, u8 *buf_attr, u32 *len_attr)
+{
+	u8 *attr_ptr = NULL;
+	u8 *target_attr_ptr = NULL;
+	u8 wfd_oui[4] = {0x50, 0x6F, 0x9A, 0x0A};
+
+	if (len_attr)
+		*len_attr = 0;
+
+	if (!wfd_ie
+	    || wfd_ielen <= 6
+	    || (wfd_ie[0] != WLAN_EID_VENDOR_SPECIFIC)
+	    || (_rtw_memcmp(wfd_ie + 2, wfd_oui, 4) != _TRUE))
+		return attr_ptr;
+
+	/* 6 = 1(Element ID) + 1(Length) + 3 (OUI) + 1(OUI Type) */
+	attr_ptr = wfd_ie + 6; /* goto first attr */
+
+	while ((attr_ptr - wfd_ie + 3) <= wfd_ielen) {
+		/* 3 = 1(Attribute ID) + 2(Length) */
+		u8 attr_id = *attr_ptr;
+		u16 attr_data_len = RTW_GET_BE16(attr_ptr + 1);
+		u16 attr_len = attr_data_len + 3;
+
+		if (0)
+			RTW_INFO("%s attr_ptr:%p, id:%u, length:%u\n", __func__, attr_ptr, attr_id, attr_data_len);
+
+		if ((attr_ptr - wfd_ie + attr_len) > wfd_ielen)
+			break;
+
+		if (attr_id == target_attr_id) {
+			target_attr_ptr = attr_ptr;
+
+			if (buf_attr)
+				_rtw_memcpy(buf_attr, attr_ptr, attr_len);
+
+			if (len_attr)
+				*len_attr = attr_len;
+
+			break;
+		} else
+			attr_ptr += attr_len;
+	}
+
+	return target_attr_ptr;
+}
+
+/**
+ * rtw_get_wfd_attr_content - Search a specific WFD attribute content from a given WFD IE
+ * @wfd_ie: Address of WFD IE to search
+ * @wfd_ielen: Length limit from wfd_ie
+ * @target_attr_id: The attribute ID of WFD attribute to search
+ * @buf_content: If not NULL and the WFD attribute is found, WFD attribute content will be copied to the buf starting from buf_content
+ * @len_content: If not NULL and the WFD attribute is found, will set to the length of the WFD attribute content
+ *
+ * Returns: the address of the specific WFD attribute content found, or NULL
+ */
+u8 *rtw_get_wfd_attr_content(u8 *wfd_ie, uint wfd_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_wfd_attr(wfd_ie, wfd_ielen, target_attr_id, NULL, &attr_len);
+
+	if (attr_ptr && attr_len) {
+		if (buf_content)
+			_rtw_memcpy(buf_content, attr_ptr + 3, attr_len - 3);
+
+		if (len_content)
+			*len_content = attr_len - 3;
+
+		return attr_ptr + 3;
+	}
+
+	return NULL;
+}
+
+uint rtw_del_wfd_ie(u8 *ies, uint ies_len_ori, const char *msg)
+{
+#define DBG_DEL_WFD_IE 0
+
+	u8 *target_ie;
+	u32 target_ie_len;
+	uint ies_len = ies_len_ori;
+	int index = 0;
+
+	while (1) {
+		target_ie = rtw_get_wfd_ie(ies, ies_len, NULL, &target_ie_len);
+		if (target_ie && target_ie_len) {
+			u8 *next_ie = target_ie + target_ie_len;
+			uint remain_len = ies_len - (next_ie - ies);
+
+			if (DBG_DEL_WFD_IE && msg) {
+				RTW_INFO("%s %d before\n", __func__, index);
+				dump_ies(RTW_DBGDUMP, ies, ies_len);
+
+				RTW_INFO("ies:%p, ies_len:%u\n", ies, ies_len);
+				RTW_INFO("target_ie:%p, target_ie_len:%u\n", target_ie, target_ie_len);
+				RTW_INFO("next_ie:%p, remain_len:%u\n", next_ie, remain_len);
+			}
+
+			_rtw_memmove(target_ie, next_ie, remain_len);
+			_rtw_memset(target_ie + remain_len, 0, target_ie_len);
+			ies_len -= target_ie_len;
+
+			if (DBG_DEL_WFD_IE && msg) {
+				RTW_INFO("%s %d after\n", __func__, index);
+				dump_ies(RTW_DBGDUMP, ies, ies_len);
+			}
+
+			index++;
+		} else
+			break;
+	}
+
+	return ies_len;
+}
+
+inline u8 *rtw_bss_ex_get_wfd_ie(WLAN_BSSID_EX *bss_ex, u8 *wfd_ie, uint *wfd_ielen)
+{
+	return rtw_get_wfd_ie(BSS_EX_TLV_IES(bss_ex), BSS_EX_TLV_IES_LEN(bss_ex), wfd_ie, wfd_ielen);
+}
+
+void rtw_bss_ex_del_wfd_ie(WLAN_BSSID_EX *bss_ex)
+{
+#define DBG_BSS_EX_DEL_WFD_IE 0
+	u8 *ies = BSS_EX_TLV_IES(bss_ex);
+	uint ies_len_ori = BSS_EX_TLV_IES_LEN(bss_ex);
+	uint ies_len;
+
+	ies_len = rtw_del_wfd_ie(ies, ies_len_ori, DBG_BSS_EX_DEL_WFD_IE ? __func__ : NULL);
+	bss_ex->IELength -= ies_len_ori - ies_len;
+}
+
+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)) {
+		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;
+			ret = _SUCCESS;
+		}
+	} else {
+
+		pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12);
+
+		if (pbuf && (wpa_ielen > 0)) {
+			if (_SUCCESS == rtw_parse_wpa2_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;
+				ret = _SUCCESS;
+			}
+		}
+	}
+
+	return ret;
+}
+
+void rtw_get_bcn_info(struct wlan_network *pnetwork)
+{
+	unsigned short cap = 0;
+	u8 bencrypt = 0;
+	/* u8 wpa_ie[255],rsn_ie[255]; */
+	u16 wpa_len = 0, rsn_len = 0;
+	struct HT_info_element *pht_info = NULL;
+	struct rtw_ieee80211_ht_cap *pht_cap = NULL;
+	unsigned int		len;
+	unsigned char		*p;
+
+	_rtw_memcpy((u8 *)&cap, rtw_get_capability_from_ie(pnetwork->network.IEs), 2);
+	cap = le16_to_cpu(cap);
+	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);
+
+	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;
+	}
+	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 rtw_ieee80211_ht_cap *)(p + 2);
+		pnetwork->BcnInfo.ht_cap_info = 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;
+}
+
+u8	rtw_ht_mcsset_to_nss(u8 *supp_mcs_set)
+{
+	u8 nss = 1;
+
+	if (supp_mcs_set[3])
+		nss = 4;
+	else if (supp_mcs_set[2])
+		nss = 3;
+	else if (supp_mcs_set[1])
+		nss = 2;
+	else if (supp_mcs_set[0])
+		nss = 1;
+	else
+		RTW_INFO("%s,%d, warning! supp_mcs_set is zero\n", __func__, __LINE__);
+	/* RTW_INFO("%s HT: %dSS\n", __FUNCTION__, nss); */
+	return nss;
+}
+
+u32	rtw_ht_mcs_set_to_bitmap(u8 *mcs_set, u8 nss)
+{
+	u8 i;
+	u32 bitmap = 0;
+
+	for (i = 0; i < nss; i++)
+		bitmap |= mcs_set[i] << (i * 8);
+
+	RTW_INFO("ht_mcs_set=%02x %02x %02x %02x, nss=%u, bitmap=%08x\n"
+		, mcs_set[0], mcs_set[1], mcs_set[2], mcs_set[3], nss, bitmap);
+
+	return bitmap;
+}
+
+/* show MCS rate, unit: 100Kbps */
+u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI, unsigned char *MCS_rate)
+{
+	u16 max_rate = 0;
+
+	if (MCS_rate[3]) {
+		if (MCS_rate[3] & BIT(7))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 6000 : 5400) : ((short_GI) ? 2889 : 2600);
+		else if (MCS_rate[3] & BIT(6))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 5400 : 4860) : ((short_GI) ? 2600 : 2340);
+		else if (MCS_rate[3] & BIT(5))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 4800 : 4320) : ((short_GI) ? 2311 : 2080);
+		else if (MCS_rate[3] & BIT(4))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 3600 : 3240) : ((short_GI) ? 1733 : 1560);
+		else if (MCS_rate[3] & BIT(3))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 2400 : 2160) : ((short_GI) ? 1156 : 1040);
+		else if (MCS_rate[3] & BIT(2))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 1800 : 1620) : ((short_GI) ? 867 : 780);
+		else if (MCS_rate[3] & BIT(1))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 1200 : 1080) : ((short_GI) ? 578 : 520);
+		else if (MCS_rate[3] & BIT(0))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 600 : 540) : ((short_GI) ? 289 : 260);
+	} else if (MCS_rate[2]) {
+		if (MCS_rate[2] & BIT(7))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 4500 : 4050) : ((short_GI) ? 2167 : 1950);
+		else if (MCS_rate[2] & BIT(6))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 4050 : 3645) : ((short_GI) ? 1950 : 1750);
+		else if (MCS_rate[2] & BIT(5))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 3600 : 3240) : ((short_GI) ? 1733 : 1560);
+		else if (MCS_rate[2] & BIT(4))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 2700 : 2430) : ((short_GI) ? 1300 : 1170);
+		else if (MCS_rate[2] & BIT(3))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 1800 : 1620) : ((short_GI) ? 867 : 780);
+		else if (MCS_rate[2] & BIT(2))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 1350 : 1215) : ((short_GI) ? 650 : 585);
+		else if (MCS_rate[2] & BIT(1))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 900 : 810) : ((short_GI) ? 433 : 390);
+		else if (MCS_rate[2] & BIT(0))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 450 : 405) : ((short_GI) ? 217 : 195);
+	} else if (MCS_rate[1]) {
+		if (MCS_rate[1] & BIT(7))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 3000 : 2700) : ((short_GI) ? 1444 : 1300);
+		else if (MCS_rate[1] & BIT(6))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 2700 : 2430) : ((short_GI) ? 1300 : 1170);
+		else if (MCS_rate[1] & BIT(5))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 2400 : 2160) : ((short_GI) ? 1156 : 1040);
+		else if (MCS_rate[1] & BIT(4))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 1800 : 1620) : ((short_GI) ? 867 : 780);
+		else if (MCS_rate[1] & BIT(3))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 1200 : 1080) : ((short_GI) ? 578 : 520);
+		else if (MCS_rate[1] & BIT(2))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 900 : 810) : ((short_GI) ? 433 : 390);
+		else if (MCS_rate[1] & BIT(1))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 600 : 540) : ((short_GI) ? 289 : 260);
+		else if (MCS_rate[1] & BIT(0))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 300 : 270) : ((short_GI) ? 144 : 130);
+	} else {
+		if (MCS_rate[0] & BIT(7))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 1500 : 1350) : ((short_GI) ? 722 : 650);
+		else if (MCS_rate[0] & BIT(6))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 1350 : 1215) : ((short_GI) ? 650 : 585);
+		else if (MCS_rate[0] & BIT(5))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 1200 : 1080) : ((short_GI) ? 578 : 520);
+		else if (MCS_rate[0] & BIT(4))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 900 : 810) : ((short_GI) ? 433 : 390);
+		else if (MCS_rate[0] & BIT(3))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 600 : 540) : ((short_GI) ? 289 : 260);
+		else if (MCS_rate[0] & BIT(2))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 450 : 405) : ((short_GI) ? 217 : 195);
+		else if (MCS_rate[0] & BIT(1))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 300 : 270) : ((short_GI) ? 144 : 130);
+		else if (MCS_rate[0] & BIT(0))
+			max_rate = (bw_40MHz) ? ((short_GI) ? 150 : 135) : ((short_GI) ? 72 : 65);
+	}
+
+	return max_rate;
+}
+
+/*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",
+};*/
+
diff --git a/drivers/staging/rtl8821ce/core/rtw_io.c b/drivers/staging/rtl8821ce/core/rtw_io.c
new file mode 100644
index 000000000000..b331e656704d
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/rtw_io.c
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * 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_IO_C_
+
+#include <drv_types.h>
+#include <hal_data.h>
+
+#if defined(CONFIG_PLATFORM_RTL8197D)
+	#define rtw_le16_to_cpu(val)		val
+	#define rtw_le32_to_cpu(val)		val
+	#define rtw_cpu_to_le16(val)		val
+	#define rtw_cpu_to_le32(val)		val
+#else
+	#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)
+#endif
+
+u8 _rtw_read8(_adapter *adapter, u32 addr)
+{
+	u8 r_val;
+	/* struct	io_queue  	*pio_queue = (struct io_queue *)adapter->pio_queue; */
+	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(_adapter *adapter, u32 addr)
+{
+	u16 r_val;
+	/* struct	io_queue  	*pio_queue = (struct io_queue *)adapter->pio_queue; */
+	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 rtw_le16_to_cpu(r_val);
+}
+
+u32 _rtw_read32(_adapter *adapter, u32 addr)
+{
+	u32 r_val;
+	/* struct	io_queue  	*pio_queue = (struct io_queue *)adapter->pio_queue; */
+	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 rtw_le32_to_cpu(r_val);
+
+}
+
+int _rtw_write8(_adapter *adapter, u32 addr, u8 val)
+{
+	/* struct	io_queue  	*pio_queue = (struct io_queue *)adapter->pio_queue; */
+	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(_adapter *adapter, u32 addr, u16 val)
+{
+	/* struct	io_queue  	*pio_queue = (struct io_queue *)adapter->pio_queue; */
+	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;
+
+	val = rtw_cpu_to_le16(val);
+	ret = _write16(pintfhdl, addr, val);
+
+	return RTW_STATUS_CODE(ret);
+}
+
+int _rtw_write32(_adapter *adapter, u32 addr, u32 val)
+{
+	/* struct	io_queue  	*pio_queue = (struct io_queue *)adapter->pio_queue; */
+	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;
+
+	val = rtw_cpu_to_le32(val);
+	ret = _write32(pintfhdl, addr, val);
+
+	return RTW_STATUS_CODE(ret);
+}
+
+u32 _rtw_write_port(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
+{
+	u32(*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
+	/* struct	io_queue  	*pio_queue = (struct io_queue *)adapter->pio_queue; */
+	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;
+}
+
+int rtw_init_io_priv(_adapter *padapter, void (*set_intf_ops)(_adapter *padapter, 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(padapter, &pintf->io_ops);
+
+	return _SUCCESS;
+}
+
+
diff --git a/drivers/staging/rtl8821ce/core/rtw_ioctl_query.c b/drivers/staging/rtl8821ce/core/rtw_ioctl_query.c
new file mode 100644
index 000000000000..4971f02a066c
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/rtw_ioctl_query.c
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * 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_IOCTL_QUERY_C_
+
+#include <drv_types.h>
+
diff --git a/drivers/staging/rtl8821ce/core/rtw_ioctl_set.c b/drivers/staging/rtl8821ce/core/rtw_ioctl_set.c
new file mode 100644
index 000000000000..e5a864f299a0
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/rtw_ioctl_set.c
@@ -0,0 +1,602 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * 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 <drv_types.h>
+#include <hal_data.h>
+
+extern void indicate_wx_scan_complete_event(_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(NDIS_802_11_SSID *ssid)
+{
+	u8	 i;
+	u8	ret = _TRUE;
+
+	if (ssid->SsidLength > 32) {
+		ret = _FALSE;
+		goto exit;
+	}
+
+#ifdef CONFIG_VALIDATE_SSID
+	for (i = 0; i < ssid->SsidLength; i++) {
+		/* wifi, printable ascii code must be supported */
+		if (!((ssid->Ssid[i] >= 0x20) && (ssid->Ssid[i] <= 0x7e))) {
+			ret = _FALSE;
+			break;
+		}
+	}
+#endif /* CONFIG_VALIDATE_SSID */
+
+exit:
+
+	return ret;
+}
+
+u8 rtw_do_join(_adapter *padapter);
+u8 rtw_do_join(_adapter *padapter)
+{
+	_irqL	irqL;
+	_list	*plist, *phead;
+	u8 *pibss = NULL;
+	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	_queue	*queue	= &(pmlmepriv->scanned_queue);
+	u8 ret = _SUCCESS;
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	pmlmepriv->cur_network.join_res = -2;
+
+	set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
+
+	pmlmepriv->pscanned = plist;
+
+	pmlmepriv->to_join = _TRUE;
+
+	if (_rtw_queue_empty(queue) == _TRUE) {
+		_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+		_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 == _FALSE
+		    || rtw_to_roam(padapter) > 0
+		   ) {
+			/* submit site_survey_cmd */
+			ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
+			if (_SUCCESS != ret) {
+				pmlmepriv->to_join = _FALSE;
+			}
+		} else {
+			pmlmepriv->to_join = _FALSE;
+			ret = _FAIL;
+		}
+
+		goto exit;
+	} else {
+		int select_ret;
+		_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+		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... */
+				WLAN_BSSID_EX    *pdev_network = &(padapter->registrypriv.dev_network);
+
+				/*pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;*/
+				init_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
+
+				pibss = padapter->registrypriv.dev_network.MacAddress;
+
+				_rtw_memset(&pdev_network->Ssid, 0, sizeof(NDIS_802_11_SSID));
+				_rtw_memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(NDIS_802_11_SSID));
+
+				rtw_update_registrypriv_dev_network(padapter);
+
+				rtw_generate_random_ibss(pibss);
+
+				if (rtw_create_ibss_cmd(padapter, 0) != _SUCCESS) {
+					ret =  _FALSE;
+					goto exit;
+				}
+
+				pmlmepriv->to_join = _FALSE;
+
+			} 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 == _FALSE
+				    || rtw_to_roam(padapter) > 0
+				   ) {
+					/* RTW_INFO("rtw_do_join() when   no desired bss in scanning queue\n"); */
+					ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
+					if (_SUCCESS != ret) {
+						pmlmepriv->to_join = _FALSE;
+					}
+				} else {
+					ret = _FAIL;
+					pmlmepriv->to_join = _FALSE;
+				}
+			}
+
+		}
+
+	}
+
+exit:
+
+	return ret;
+}
+
+u8 rtw_set_802_11_bssid(_adapter *padapter, u8 *bssid)
+{
+	_irqL irqL;
+	u8 status = _SUCCESS;
+
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+	RTW_PRINT("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;
+	}
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	RTW_INFO("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) == _TRUE)
+		goto release_mlme_lock;
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE) == _TRUE) {
+
+		if (_rtw_memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, ETH_ALEN) == _TRUE) {
+			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 {
+
+			rtw_disassoc_cmd(padapter, 0, 0);
+
+			if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
+				rtw_indicate_disconnect(padapter, 0, _FALSE);
+
+			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 (rtw_handle_tkip_countermeasure(padapter, __func__) == _FAIL) {
+		status = _FAIL;
+		goto release_mlme_lock;
+	}
+
+	_rtw_memset(&pmlmepriv->assoc_ssid, 0, sizeof(NDIS_802_11_SSID));
+	_rtw_memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN);
+	pmlmepriv->assoc_by_bssid = _TRUE;
+
+	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE)
+		pmlmepriv->to_join = _TRUE;
+	else
+		status = rtw_do_join(padapter);
+
+release_mlme_lock:
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+exit:
+
+	return status;
+}
+
+u8 rtw_set_802_11_ssid(_adapter *padapter, NDIS_802_11_SSID *ssid)
+{
+	_irqL irqL;
+	u8 status = _SUCCESS;
+	u32 cur_time = 0;
+
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct wlan_network *pnetwork = &pmlmepriv->cur_network;
+
+	RTW_PRINT("set ssid [%s] fw_state=0x%08x\n",
+		  ssid->Ssid, get_fwstate(pmlmepriv));
+
+	if (!rtw_is_hw_init_completed(padapter)) {
+		status = _FAIL;
+		goto exit;
+	}
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	RTW_INFO("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) == _TRUE) {
+
+		if ((pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength) &&
+		    (_rtw_memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, ssid->SsidLength) == _TRUE)) {
+			if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _FALSE)) {
+
+				if (rtw_is_same_ibss(padapter, pnetwork) == _FALSE) {
+					/* if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again */
+					rtw_disassoc_cmd(padapter, 0, 0);
+
+					if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
+						rtw_indicate_disconnect(padapter, 0, _FALSE);
+
+					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 {
+
+			rtw_disassoc_cmd(padapter, 0, 0);
+
+			if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
+				rtw_indicate_disconnect(padapter, 0, _FALSE);
+
+			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 (rtw_handle_tkip_countermeasure(padapter, __func__) == _FAIL) {
+		status = _FAIL;
+		goto release_mlme_lock;
+	}
+
+	if (rtw_validate_ssid(ssid) == _FALSE) {
+		status = _FAIL;
+		goto release_mlme_lock;
+	}
+
+	_rtw_memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(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:
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+exit:
+
+	return status;
+
+}
+
+u8 rtw_set_802_11_infrastructure_mode(_adapter *padapter,
+			      NDIS_802_11_NETWORK_INFRASTRUCTURE networktype)
+{
+	_irqL irqL;
+	struct	mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct	wlan_network	*cur_network = &pmlmepriv->cur_network;
+	NDIS_802_11_NETWORK_INFRASTRUCTURE *pold_state = &(cur_network->network.InfrastructureMode);
+
+	if (*pold_state != networktype) {
+		/* RTW_INFO("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;
+
+			stop_ap_mode(padapter);
+		}
+
+		_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+		if ((check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) || (*pold_state == Ndis802_11IBSS))
+			rtw_disassoc_cmd(padapter, 0, 0);
+
+		if ((check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ||
+		    (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE))
+			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, 0, _FALSE); /*will clr Linked_state; before this function, we must have checked 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);
+			start_ap_mode(padapter);
+			/* rtw_indicate_connect(padapter); */
+
+			break;
+
+		case Ndis802_11AutoUnknown:
+		case Ndis802_11InfrastructureMax:
+			break;
+		case Ndis802_11Monitor:
+			set_fwstate(pmlmepriv, WIFI_MONITOR_STATE);
+			break;
+		}
+
+		/* SecClearAllKeys(adapter); */
+
+		_exit_critical_bh(&pmlmepriv->lock, &irqL);
+	}
+
+	return _TRUE;
+}
+
+u8 rtw_set_802_11_disassociate(_adapter *padapter)
+{
+	_irqL irqL;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) {
+
+		rtw_disassoc_cmd(padapter, 0, 0);
+		rtw_indicate_disconnect(padapter, 0, _FALSE);
+		/* modify for CONFIG_IEEE80211W, none 11w can use it */
+		rtw_free_assoc_resources_cmd(padapter);
+		if (_FAIL == rtw_pwr_wakeup(padapter))
+			RTW_INFO("%s(): rtw_pwr_wakeup fail !!!\n", __FUNCTION__);
+	}
+
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+	return _TRUE;
+}
+
+u8 rtw_set_802_11_bssid_list_scan(_adapter *padapter, NDIS_802_11_SSID *pssid, int ssid_max_num, struct rtw_ieee80211_channel *ch, int ch_num)
+{
+	_irqL	irqL;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	u8	res = _TRUE;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+	res = rtw_sitesurvey_cmd(padapter, pssid, ssid_max_num, ch, ch_num);
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+	return res;
+}
+
+u8 rtw_set_802_11_authentication_mode(_adapter *padapter, NDIS_802_11_AUTHENTICATION_MODE authmode)
+{
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	int res;
+	u8 ret;
+
+	psecuritypriv->ndisauthtype = authmode;
+
+	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(_adapter *padapter, NDIS_802_11_WEP *wep)
+{
+
+	u8		bdefaultkey;
+	u8		btransmitkey;
+	sint		keyid, res;
+	struct security_priv *psecuritypriv = &(padapter->securitypriv);
+	u8		ret = _SUCCESS;
+
+	bdefaultkey = (wep->KeyIndex & 0x40000000) > 0 ? _FALSE : _TRUE; /* for ??? */
+	btransmitkey = (wep->KeyIndex & 0x80000000) > 0 ? _TRUE  : _FALSE;	/* for ??? */
+	keyid = wep->KeyIndex & 0x3fffffff;
+
+	if (keyid >= 4) {
+		ret = _FALSE;
+		goto exit;
+	}
+
+	switch (wep->KeyLength) {
+	case 5:
+		psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
+		break;
+	case 13:
+		psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
+		break;
+	default:
+		psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
+		break;
+	}
+
+	_rtw_memcpy(&(psecuritypriv->dot11DefKey[keyid].skey[0]), &(wep->KeyMaterial), wep->KeyLength);
+
+	psecuritypriv->dot11DefKeylen[keyid] = wep->KeyLength;
+
+	psecuritypriv->dot11PrivacyKeyIndex = keyid;
+
+	res = rtw_set_key(padapter, psecuritypriv, keyid, 1, _TRUE);
+
+	if (res == _FAIL)
+		ret = _FALSE;
+exit:
+
+	return ret;
+
+}
+
+/*
+* rtw_get_cur_max_rate -
+* @adapter: pointer to _adapter structure
+*
+* Return 0 or 100Kbps
+*/
+u16 rtw_get_cur_max_rate(_adapter *adapter)
+{
+	int	i = 0;
+	u16	rate = 0, max_rate = 0;
+	struct mlme_priv	*pmlmepriv = &adapter->mlmepriv;
+	WLAN_BSSID_EX	*pcur_bss = &pmlmepriv->cur_network.network;
+	struct sta_info *psta = NULL;
+	u8	short_GI = 0;
+	u8	rf_type = 0;
+
+	if (adapter->registrypriv.mp_mode == 1) {
+		if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE)
+			return 0;
+	}
+
+	if ((check_fwstate(pmlmepriv, _FW_LINKED) != _TRUE)
+	    && (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) != _TRUE))
+		return 0;
+
+	psta = rtw_get_stainfo(&adapter->stapriv, get_bssid(pmlmepriv));
+	if (psta == NULL)
+		return 0;
+
+	short_GI = query_ra_short_GI(psta, psta->bw_mode);
+
+	if (is_supported_ht(psta->wireless_mode)) {
+		rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+		max_rate = rtw_mcs_rate(rf_type
+			, (psta->bw_mode == CHANNEL_WIDTH_40) ? 1 : 0
+			, short_GI
+			, psta->htpriv.ht_cap.supp_mcs_set
+		);
+	}
+	else if (is_supported_vht(psta->wireless_mode))
+		max_rate = ((rtw_vht_mcs_to_data_rate(psta->bw_mode, short_GI, pmlmepriv->vhtpriv.vht_highest_rate) + 1) >> 1) * 10;
+	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_channel_plan -
+* @adapter: pointer to _adapter structure
+* @channel_plan:
+*
+* Return _SUCCESS or _FAIL
+*/
+int rtw_set_channel_plan(_adapter *adapter, u8 channel_plan)
+{
+	struct registry_priv *pregistrypriv = &adapter->registrypriv;
+	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+
+	/* handle by cmd_thread to sync with scan operation */
+	return rtw_set_chplan_cmd(adapter, RTW_CMDF_WAIT_ACK, channel_plan, 1);
+}
+
+/*
+* rtw_set_country -
+* @adapter: pointer to _adapter structure
+* @country_code: string of country code
+*
+* Return _SUCCESS or _FAIL
+*/
+int rtw_set_country(_adapter *adapter, const char *country_code)
+{
+#ifdef CONFIG_RTW_IOCTL_SET_COUNTRY
+	return rtw_set_country_cmd(adapter, RTW_CMDF_WAIT_ACK, country_code, 1);
+#else
+	return _FAIL;
+#endif
+}
+
+/*
+* rtw_set_band -
+* @adapter: pointer to _adapter structure
+* @band: band to set
+*
+* Return _SUCCESS or _FAIL
+*/
+int rtw_set_band(_adapter *adapter, u8 band)
+{
+	if (rtw_band_valid(band)) {
+		RTW_INFO(FUNC_ADPT_FMT" band:%d\n", FUNC_ADPT_ARG(adapter), band);
+		adapter->setband = band;
+		return _SUCCESS;
+	}
+
+	RTW_PRINT(FUNC_ADPT_FMT" band:%d fail\n", FUNC_ADPT_ARG(adapter), band);
+	return _FAIL;
+}
diff --git a/drivers/staging/rtl8821ce/core/rtw_mi.c b/drivers/staging/rtl8821ce/core/rtw_mi.c
new file mode 100644
index 000000000000..ba80d27371b5
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/rtw_mi.c
@@ -0,0 +1,834 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2015 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_MI_C_
+
+#include <drv_types.h>
+#include <hal_data.h>
+
+void rtw_mi_update_union_chan_inf(_adapter *adapter, u8 ch, u8 offset , u8 bw)
+{
+	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+	struct mi_state *iface_state = &dvobj->iface_state;
+
+	iface_state->union_ch = ch;
+	iface_state->union_bw = bw;
+	iface_state->union_offset = offset;
+}
+
+/* Find union about ch, bw, ch_offset of all linked/linking interfaces */
+int _rtw_mi_get_ch_setting_union(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset, bool include_self)
+{
+	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+	_adapter *iface;
+	struct mlme_ext_priv *mlmeext;
+	int i;
+	u8 ch_ret = 0;
+	u8 bw_ret = CHANNEL_WIDTH_20;
+	u8 offset_ret = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	int num = 0;
+
+	if (ch)
+		*ch = 0;
+	if (bw)
+		*bw = CHANNEL_WIDTH_20;
+	if (offset)
+		*offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		iface = dvobj->padapters[i];
+		mlmeext = &iface->mlmeextpriv;
+
+		if (!check_fwstate(&iface->mlmepriv, _FW_LINKED | _FW_UNDER_LINKING))
+			continue;
+
+		if (check_fwstate(&iface->mlmepriv, WIFI_OP_CH_SWITCHING))
+			continue;
+
+		if (include_self == _FALSE && adapter == iface)
+			continue;
+
+		if (num == 0) {
+			ch_ret = mlmeext->cur_channel;
+			bw_ret = mlmeext->cur_bwmode;
+			offset_ret = mlmeext->cur_ch_offset;
+			num++;
+			continue;
+		}
+
+		if (ch_ret != mlmeext->cur_channel) {
+			num = 0;
+			break;
+		}
+
+		if (bw_ret < mlmeext->cur_bwmode) {
+			bw_ret = mlmeext->cur_bwmode;
+			offset_ret = mlmeext->cur_ch_offset;
+		} else if (bw_ret == mlmeext->cur_bwmode && offset_ret != mlmeext->cur_ch_offset) {
+			num = 0;
+			break;
+		}
+
+		num++;
+	}
+
+	if (num) {
+		if (ch)
+			*ch = ch_ret;
+		if (bw)
+			*bw = bw_ret;
+		if (offset)
+			*offset = offset_ret;
+	}
+
+	return num;
+}
+
+inline int rtw_mi_get_ch_setting_union(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset)
+{
+	return _rtw_mi_get_ch_setting_union(adapter, ch, bw, offset, 1);
+}
+
+inline int rtw_mi_get_ch_setting_union_no_self(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset)
+{
+	return _rtw_mi_get_ch_setting_union(adapter, ch, bw, offset, 0);
+}
+
+/* For now, not return union_ch/bw/offset */
+void _rtw_mi_status(_adapter *adapter, struct mi_state *mstate, bool include_self)
+{
+	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+	_adapter *iface;
+	int i;
+
+	_rtw_memset(mstate, 0, sizeof(struct mi_state));
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		iface = dvobj->padapters[i];
+
+		if (include_self == _FALSE && iface == adapter)
+			continue;
+
+		if (check_fwstate(&iface->mlmepriv, WIFI_STATION_STATE) == _TRUE) {
+			MSTATE_STA_NUM(mstate)++;
+			if (check_fwstate(&iface->mlmepriv, _FW_LINKED) == _TRUE)
+				MSTATE_STA_LD_NUM(mstate)++;
+
+			if (check_fwstate(&iface->mlmepriv, _FW_UNDER_LINKING) == _TRUE)
+				MSTATE_STA_LG_NUM(mstate)++;
+
+		} else if (check_fwstate(&iface->mlmepriv, WIFI_AP_STATE) == _TRUE
+			&& check_fwstate(&iface->mlmepriv, _FW_LINKED) == _TRUE
+		) {
+			MSTATE_AP_NUM(mstate)++;
+			if (iface->stapriv.asoc_sta_count > 2)
+				MSTATE_AP_LD_NUM(mstate)++;
+
+		} else if (check_fwstate(&iface->mlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE) == _TRUE
+			&& check_fwstate(&iface->mlmepriv, _FW_LINKED) == _TRUE
+		) {
+			MSTATE_ADHOC_NUM(mstate)++;
+			if (iface->stapriv.asoc_sta_count > 2)
+				MSTATE_ADHOC_LD_NUM(mstate)++;
+		}
+
+		if (check_fwstate(&iface->mlmepriv, WIFI_UNDER_WPS) == _TRUE)
+			MSTATE_WPS_NUM(mstate)++;
+
+
+	}
+}
+
+inline void rtw_mi_status(_adapter *adapter, struct mi_state *mstate)
+{
+	return _rtw_mi_status(adapter, mstate, 1);
+}
+inline void rtw_mi_status_no_self(_adapter *adapter, struct mi_state *mstate)
+{
+	return _rtw_mi_status(adapter, mstate, 0);
+}
+void dump_mi_status(void *sel, struct dvobj_priv *dvobj)
+{
+	RTW_PRINT_SEL(sel, "== dvobj-iface_state ==\n");
+	RTW_PRINT_SEL(sel, "sta_num:%d\n", DEV_STA_NUM(dvobj));
+	RTW_PRINT_SEL(sel, "linking_sta_num:%d\n", DEV_STA_LG_NUM(dvobj));
+	RTW_PRINT_SEL(sel, "linked_sta_num:%d\n", DEV_STA_LD_NUM(dvobj));
+	RTW_PRINT_SEL(sel, "ap_num:%d\n", DEV_AP_NUM(dvobj));
+	RTW_PRINT_SEL(sel, "linked_ap_num:%d\n", DEV_AP_LD_NUM(dvobj));
+	RTW_PRINT_SEL(sel, "adhoc_num:%d\n", DEV_ADHOC_NUM(dvobj));
+	RTW_PRINT_SEL(sel, "linked_adhoc_num:%d\n", DEV_ADHOC_LD_NUM(dvobj));
+	RTW_PRINT_SEL(sel, "p2p_device_num:%d\n", rtw_mi_stay_in_p2p_mode(dvobj->padapters[IFACE_ID0]));
+	RTW_PRINT_SEL(sel, "under_wps_num:%d\n", DEV_WPS_NUM(dvobj));
+	RTW_PRINT_SEL(sel, "union_ch:%d\n", DEV_U_CH(dvobj));
+	RTW_PRINT_SEL(sel, "union_bw:%d\n", DEV_U_BW(dvobj));
+	RTW_PRINT_SEL(sel, "union_offset:%d\n", DEV_U_OFFSET(dvobj));
+	RTW_PRINT_SEL(sel, "================\n\n");
+}
+
+inline void rtw_mi_update_iface_status(struct mlme_priv *pmlmepriv, sint state)
+{
+	_adapter *adapter = container_of(pmlmepriv, _adapter, mlmepriv);
+	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+	struct mi_state *iface_state = &dvobj->iface_state;
+	struct mi_state tmp_mstate;
+	u8 i;
+	u8 u_ch, u_offset, u_bw;
+	_adapter *iface;
+
+	if (state == WIFI_MONITOR_STATE
+		|| state == WIFI_SITE_MONITOR
+		|| state == 0xFFFFFFFF
+	)
+		return;
+
+	if (0)
+		RTW_INFO("%s => will change or clean state to 0x%08x\n", __func__, state);
+
+	rtw_mi_status(adapter, &tmp_mstate);
+	_rtw_memcpy(iface_state, &tmp_mstate, sizeof(struct mi_state));
+
+	if (rtw_mi_get_ch_setting_union(adapter, &u_ch, &u_bw, &u_offset))
+		rtw_mi_update_union_chan_inf(adapter , u_ch, u_offset , u_bw);
+	else {
+		if (0) {
+			dump_adapters_status(RTW_DBGDUMP , dvobj);
+			RTW_INFO("%s-[ERROR] cannot get union channel\n", __func__);
+			rtw_warn_on(1);
+		}
+	}
+
+}
+u8 rtw_mi_check_status(_adapter *adapter, u8 type)
+{
+	struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+	struct mi_state *iface_state = &dvobj->iface_state;
+	u8 ret = _FALSE;
+
+
+	switch (type) {
+	case MI_LINKED:
+		if (MSTATE_STA_LD_NUM(iface_state) || MSTATE_AP_NUM(iface_state) || MSTATE_ADHOC_NUM(iface_state)) /*check_fwstate(&iface->mlmepriv, _FW_LINKED)*/
+			ret = _TRUE;
+		break;
+	case MI_ASSOC:
+		if (MSTATE_STA_LD_NUM(iface_state) || MSTATE_AP_LD_NUM(iface_state) || MSTATE_ADHOC_LD_NUM(iface_state))
+			ret = _TRUE;
+		break;
+	case MI_UNDER_WPS:
+		if (MSTATE_WPS_NUM(iface_state))
+			ret = _TRUE;
+		break;
+
+	case MI_AP_MODE:
+		if (MSTATE_AP_NUM(iface_state))
+			ret = _TRUE;
+		break;
+	case MI_AP_ASSOC:
+		if (MSTATE_AP_LD_NUM(iface_state))
+			ret = _TRUE;
+		break;
+
+	case MI_ADHOC:
+		if (MSTATE_ADHOC_NUM(iface_state))
+			ret = _TRUE;
+		break;
+	case MI_ADHOC_ASSOC:
+		if (MSTATE_ADHOC_LD_NUM(iface_state))
+			ret = _TRUE;
+		break;
+
+	case MI_STA_NOLINK: /* this is misleading, but not used now */
+		if (MSTATE_STA_NUM(iface_state) && (!(MSTATE_STA_LD_NUM(iface_state) || MSTATE_STA_LG_NUM(iface_state))))
+			ret = _TRUE;
+		break;
+	case MI_STA_LINKED:
+		if (MSTATE_STA_LD_NUM(iface_state))
+			ret = _TRUE;
+		break;
+	case MI_STA_LINKING:
+		if (MSTATE_STA_LG_NUM(iface_state))
+			ret = _TRUE;
+		break;
+
+	default:
+		break;
+	}
+	return ret;
+}
+
+u8 rtw_mi_mp_mode_check(_adapter *padapter)
+{
+	if (padapter->registrypriv.mp_mode == 1)
+		return _TRUE;
+	return _FALSE;
+}
+
+/*
+* return value : 0 is failed or have not interface meet condition
+* return value : !0 is success or interface numbers which meet condition
+* return value of ops_func must be _TRUE or _FALSE
+*/
+static u8 _rtw_mi_process(_adapter *padapter, bool exclude_self,
+		  void *data, u8(*ops_func)(_adapter *padapter, void *data))
+{
+	int i;
+	_adapter *iface;
+	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+
+	u8 ret = 0;
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		iface = dvobj->padapters[i];
+		if ((iface) && rtw_is_adapter_up(iface)) {
+
+			if ((exclude_self) && (iface == padapter))
+				continue;
+
+			if (ops_func)
+				if (_TRUE == ops_func(iface, data))
+					ret++;
+		}
+	}
+	return ret;
+}
+static u8 _rtw_mi_process_without_schk(_adapter *padapter, bool exclude_self,
+		  void *data, u8(*ops_func)(_adapter *padapter, void *data))
+{
+	int i;
+	_adapter *iface;
+	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+
+	u8 ret = 0;
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		iface = dvobj->padapters[i];
+		if (iface) {
+			if ((exclude_self) && (iface == padapter))
+				continue;
+
+			if (ops_func)
+				if (ops_func(iface, data) == _TRUE)
+					ret++;
+		}
+	}
+	return ret;
+}
+
+static u8 _rtw_mi_netif_stop_queue(_adapter *padapter, void *data)
+{
+	bool carrier_off = *(bool *)data;
+	struct net_device *pnetdev = padapter->pnetdev;
+
+	if (carrier_off)
+		netif_carrier_off(pnetdev);
+	rtw_netif_stop_queue(pnetdev);
+	return _TRUE;
+}
+u8 rtw_mi_netif_stop_queue(_adapter *padapter, bool carrier_off)
+{
+	bool in_data = carrier_off;
+
+	return _rtw_mi_process(padapter, _FALSE, &in_data, _rtw_mi_netif_stop_queue);
+}
+u8 rtw_mi_buddy_netif_stop_queue(_adapter *padapter, bool carrier_off)
+{
+	bool in_data = carrier_off;
+
+	return _rtw_mi_process(padapter, _TRUE, &in_data, _rtw_mi_netif_stop_queue);
+}
+
+static u8 _rtw_mi_netif_wake_queue(_adapter *padapter, void *data)
+{
+	struct net_device *pnetdev = padapter->pnetdev;
+
+	if (pnetdev)
+		rtw_netif_wake_queue(pnetdev);
+	return _TRUE;
+}
+u8 rtw_mi_netif_wake_queue(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_netif_wake_queue);
+}
+u8 rtw_mi_buddy_netif_wake_queue(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_netif_wake_queue);
+}
+
+static u8 _rtw_mi_netif_carrier_on(_adapter *padapter, void *data)
+{
+	struct net_device *pnetdev = padapter->pnetdev;
+
+	if (pnetdev)
+		rtw_netif_carrier_on(pnetdev);
+	return _TRUE;
+}
+u8 rtw_mi_netif_carrier_on(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_netif_carrier_on);
+}
+u8 rtw_mi_buddy_netif_carrier_on(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_netif_carrier_on);
+}
+
+static u8 _rtw_mi_scan_abort(_adapter *adapter, void *data)
+{
+	bool bwait = *(bool *)data;
+
+	if (bwait)
+		rtw_scan_abort(adapter);
+	else
+		rtw_scan_abort_no_wait(adapter);
+
+	return _TRUE;
+}
+void rtw_mi_scan_abort(_adapter *adapter, bool bwait)
+{
+	bool in_data = bwait;
+
+	_rtw_mi_process(adapter, _FALSE, &in_data, _rtw_mi_scan_abort);
+
+}
+void rtw_mi_buddy_scan_abort(_adapter *adapter, bool bwait)
+{
+	bool in_data = bwait;
+
+	_rtw_mi_process(adapter, _TRUE, &in_data, _rtw_mi_scan_abort);
+}
+
+static u8 _rtw_mi_start_drv_threads(_adapter *adapter, void *data)
+{
+	rtw_start_drv_threads(adapter);
+	return _TRUE;
+}
+void rtw_mi_start_drv_threads(_adapter *adapter)
+{
+	_rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_start_drv_threads);
+}
+void rtw_mi_buddy_start_drv_threads(_adapter *adapter)
+{
+	_rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_start_drv_threads);
+}
+
+static u8 _rtw_mi_stop_drv_threads(_adapter *adapter, void *data)
+{
+	rtw_stop_drv_threads(adapter);
+	return _TRUE;
+}
+void rtw_mi_stop_drv_threads(_adapter *adapter)
+{
+	_rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_stop_drv_threads);
+}
+void rtw_mi_buddy_stop_drv_threads(_adapter *adapter)
+{
+	_rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_stop_drv_threads);
+}
+
+static u8 _rtw_mi_cancel_all_timer(_adapter *adapter, void *data)
+{
+	rtw_cancel_all_timer(adapter);
+	return _TRUE;
+}
+void rtw_mi_cancel_all_timer(_adapter *adapter)
+{
+	_rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_cancel_all_timer);
+}
+void rtw_mi_buddy_cancel_all_timer(_adapter *adapter)
+{
+	_rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_cancel_all_timer);
+}
+
+static u8 _rtw_mi_reset_drv_sw(_adapter *adapter, void *data)
+{
+	rtw_reset_drv_sw(adapter);
+	return _TRUE;
+}
+void rtw_mi_reset_drv_sw(_adapter *adapter)
+{
+	_rtw_mi_process_without_schk(adapter, _FALSE, NULL, _rtw_mi_reset_drv_sw);
+}
+void rtw_mi_buddy_reset_drv_sw(_adapter *adapter)
+{
+	_rtw_mi_process_without_schk(adapter, _TRUE, NULL, _rtw_mi_reset_drv_sw);
+}
+
+static u8 _rtw_mi_intf_start(_adapter *adapter, void *data)
+{
+	rtw_intf_start(adapter);
+	return _TRUE;
+}
+void rtw_mi_intf_start(_adapter *adapter)
+{
+	_rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_intf_start);
+}
+void rtw_mi_buddy_intf_start(_adapter *adapter)
+{
+	_rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_intf_start);
+}
+
+static u8 _rtw_mi_intf_stop(_adapter *adapter, void *data)
+{
+	rtw_intf_stop(adapter);
+	return _TRUE;
+}
+void rtw_mi_intf_stop(_adapter *adapter)
+{
+	_rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_intf_stop);
+}
+void rtw_mi_buddy_intf_stop(_adapter *adapter)
+{
+	_rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_intf_stop);
+}
+
+static u8 _rtw_mi_suspend_free_assoc_resource(_adapter *padapter, void *data)
+{
+	return rtw_suspend_free_assoc_resource(padapter);
+}
+void rtw_mi_suspend_free_assoc_resource(_adapter *adapter)
+{
+	_rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_suspend_free_assoc_resource);
+}
+void rtw_mi_buddy_suspend_free_assoc_resource(_adapter *adapter)
+{
+	_rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_suspend_free_assoc_resource);
+}
+
+static u8 _rtw_mi_is_scan_deny(_adapter *adapter, void *data)
+{
+	return rtw_is_scan_deny(adapter);
+}
+
+u8 rtw_mi_is_scan_deny(_adapter *adapter)
+{
+	return _rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_is_scan_deny);
+
+}
+u8 rtw_mi_buddy_is_scan_deny(_adapter *adapter)
+{
+	return _rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_is_scan_deny);
+}
+
+
+struct nulldata_param {
+	unsigned char *da;
+	unsigned int power_mode;
+	int try_cnt;
+	int wait_ms;
+};
+
+static u8 _rtw_mi_issue_nulldata(_adapter *padapter, void *data)
+{
+	struct nulldata_param *pnulldata_param = (struct nulldata_param *)data;
+
+	if (is_client_associated_to_ap(padapter) == _TRUE) {
+		/* TODO: TDLS peers */
+		issue_nulldata(padapter, pnulldata_param->da, pnulldata_param->power_mode, pnulldata_param->try_cnt, pnulldata_param->wait_ms);
+		return _TRUE;
+	}
+	return _FALSE;
+}
+
+u8 rtw_mi_issue_nulldata(_adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms)
+{
+	struct nulldata_param nparam;
+
+	nparam.da = da;
+	nparam.power_mode = power_mode;/*0 or 1*/
+	nparam.try_cnt = try_cnt;
+	nparam.wait_ms = wait_ms;
+
+	return _rtw_mi_process(padapter, _FALSE, &nparam, _rtw_mi_issue_nulldata);
+}
+u8 rtw_mi_buddy_issue_nulldata(_adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms)
+{
+	struct nulldata_param nparam;
+
+	nparam.da = da;
+	nparam.power_mode = power_mode;
+	nparam.try_cnt = try_cnt;
+	nparam.wait_ms = wait_ms;
+
+	return _rtw_mi_process(padapter, _TRUE, &nparam, _rtw_mi_issue_nulldata);
+}
+
+static u8 _rtw_mi_beacon_update(_adapter *padapter, void *data)
+{
+	struct mlme_ext_priv *mlmeext = &padapter->mlmeextpriv;
+
+	if (mlmeext_msr(mlmeext) == WIFI_FW_AP_STATE
+	    && check_fwstate(&padapter->mlmepriv, _FW_LINKED) == _TRUE) {
+		RTW_INFO(ADPT_FMT"-WIFI_FW_AP_STATE - update_beacon\n", ADPT_ARG(padapter));
+		update_beacon(padapter, 0, NULL, _TRUE);
+	}
+	return _TRUE;
+}
+
+void rtw_mi_beacon_update(_adapter *padapter)
+{
+	_rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_beacon_update);
+}
+
+void rtw_mi_buddy_beacon_update(_adapter *padapter)
+{
+	_rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_beacon_update);
+}
+
+static u8 _rtw_mi_hal_dump_macaddr(_adapter *padapter, void *data)
+{
+	u8 mac_addr[ETH_ALEN] = {0};
+
+	rtw_hal_get_macaddr_port(padapter, mac_addr);
+	RTW_INFO(ADPT_FMT"MAC Address ="MAC_FMT"\n", ADPT_ARG(padapter), MAC_ARG(mac_addr));
+	return _TRUE;
+}
+void rtw_mi_hal_dump_macaddr(_adapter *padapter)
+{
+	_rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_hal_dump_macaddr);
+}
+void rtw_mi_buddy_hal_dump_macaddr(_adapter *padapter)
+{
+	_rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_hal_dump_macaddr);
+}
+
+static u8 _rtw_mi_xmit_tasklet_schedule(_adapter *padapter, void *data)
+{
+	if (rtw_txframes_pending(padapter)) {
+		/* try to deal with the pending packets */
+		tasklet_hi_schedule(&(padapter->xmitpriv.xmit_tasklet));
+	}
+	return _TRUE;
+}
+void rtw_mi_xmit_tasklet_schedule(_adapter *padapter)
+{
+	_rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_xmit_tasklet_schedule);
+}
+void rtw_mi_buddy_xmit_tasklet_schedule(_adapter *padapter)
+{
+	_rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_xmit_tasklet_schedule);
+}
+
+u8 _rtw_mi_busy_traffic_check(_adapter *padapter, void *data)
+{
+	u32 passtime;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	bool check_sc_interval = *(bool *)data;
+
+	if (pmlmepriv->LinkDetectInfo.bBusyTraffic == _TRUE) {
+		if (check_sc_interval) {
+			/* Miracast can't do AP scan*/
+			passtime = rtw_get_passing_time_ms(pmlmepriv->lastscantime);
+			pmlmepriv->lastscantime = rtw_get_current_time();
+			if (passtime > BUSY_TRAFFIC_SCAN_DENY_PERIOD) {
+				RTW_INFO(ADPT_FMT" bBusyTraffic == _TRUE\n", ADPT_ARG(padapter));
+				return _TRUE;
+			}
+		} else
+			return _TRUE;
+	}
+
+	return _FALSE;
+}
+
+u8 rtw_mi_busy_traffic_check(_adapter *padapter, bool check_sc_interval)
+{
+	bool in_data = check_sc_interval;
+
+	return _rtw_mi_process(padapter, _FALSE, &in_data, _rtw_mi_busy_traffic_check);
+}
+u8 rtw_mi_buddy_busy_traffic_check(_adapter *padapter, bool check_sc_interval)
+{
+	bool in_data = check_sc_interval;
+
+	return _rtw_mi_process(padapter, _TRUE, &in_data, _rtw_mi_busy_traffic_check);
+}
+static u8 _rtw_mi_check_mlmeinfo_state(_adapter *padapter, void *data)
+{
+	u32 state = *(u32 *)data;
+	struct mlme_ext_priv *mlmeext = &padapter->mlmeextpriv;
+
+	/*if (mlmeext_msr(mlmeext) == state)*/
+	if (check_mlmeinfo_state(mlmeext, state))
+		return _TRUE;
+	else
+		return _FALSE;
+}
+
+u8 rtw_mi_check_mlmeinfo_state(_adapter *padapter, u32 state)
+{
+	u32 in_data = state;
+
+	return _rtw_mi_process(padapter, _FALSE, &in_data, _rtw_mi_check_mlmeinfo_state);
+}
+
+u8 rtw_mi_buddy_check_mlmeinfo_state(_adapter *padapter, u32 state)
+{
+	u32 in_data = state;
+
+	return _rtw_mi_process(padapter, _TRUE, &in_data, _rtw_mi_check_mlmeinfo_state);
+}
+
+
+static u8 _rtw_mi_check_fwstate(_adapter *padapter, void *data)
+{
+	u8 ret = _FALSE;
+
+	sint state = *(sint *)data;
+
+	if ((state == WIFI_FW_NULL_STATE) &&
+	    (padapter->mlmepriv.fw_state == WIFI_FW_NULL_STATE))
+		ret = _TRUE;
+	else if (_TRUE == check_fwstate(&padapter->mlmepriv, state))
+		ret = _TRUE;
+	return ret;
+}
+u8 rtw_mi_check_fwstate(_adapter *padapter, sint state)
+{
+	sint in_data = state;
+
+	return _rtw_mi_process(padapter, _FALSE, &in_data, _rtw_mi_check_fwstate);
+}
+u8 rtw_mi_buddy_check_fwstate(_adapter *padapter, sint state)
+{
+	sint in_data = state;
+
+	return _rtw_mi_process(padapter, _TRUE, &in_data, _rtw_mi_check_fwstate);
+}
+
+static u8 _rtw_mi_traffic_statistics(_adapter *padapter , void *data)
+{
+	struct dvobj_priv	*pdvobjpriv = adapter_to_dvobj(padapter);
+
+	/* Tx */
+	pdvobjpriv->traffic_stat.tx_bytes += padapter->xmitpriv.tx_bytes;
+	pdvobjpriv->traffic_stat.tx_pkts += padapter->xmitpriv.tx_pkts;
+	pdvobjpriv->traffic_stat.tx_drop += padapter->xmitpriv.tx_drop;
+
+	/* Rx */
+	pdvobjpriv->traffic_stat.rx_bytes += padapter->recvpriv.rx_bytes;
+	pdvobjpriv->traffic_stat.rx_pkts += padapter->recvpriv.rx_pkts;
+	pdvobjpriv->traffic_stat.rx_drop += padapter->recvpriv.rx_drop;
+	return _TRUE;
+}
+u8 rtw_mi_traffic_statistics(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_traffic_statistics);
+}
+
+static u8 _rtw_mi_check_miracast_enabled(_adapter *padapter , void *data)
+{
+	return is_miracast_enabled(padapter);
+}
+u8 rtw_mi_check_miracast_enabled(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_check_miracast_enabled);
+}
+
+static u8 _rtw_mi_dynamic_check_timer_handlder(_adapter *adapter, void *data)
+{
+	rtw_iface_dynamic_check_timer_handlder(adapter);
+	return _TRUE;
+}
+u8 rtw_mi_dynamic_check_timer_handlder(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_dynamic_check_timer_handlder);
+}
+
+static u8 _rtw_mi_dynamic_chk_wk_hdl(_adapter *adapter, void *data)
+{
+	rtw_iface_dynamic_chk_wk_hdl(adapter);
+	return _TRUE;
+}
+u8 rtw_mi_dynamic_chk_wk_hdl(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_dynamic_chk_wk_hdl);
+}
+
+static u8 _rtw_mi_os_xmit_schedule(_adapter *adapter, void *data)
+{
+	rtw_os_xmit_schedule(adapter);
+	return _TRUE;
+}
+u8 rtw_mi_os_xmit_schedule(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_os_xmit_schedule);
+}
+u8 rtw_mi_buddy_os_xmit_schedule(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_os_xmit_schedule);
+}
+
+static u8 _rtw_mi_report_survey_event(_adapter *adapter, void *data)
+{
+	union recv_frame *precv_frame = (union recv_frame *)data;
+
+	report_survey_event(adapter, precv_frame);
+	return _TRUE;
+}
+u8 rtw_mi_report_survey_event(_adapter *padapter, union recv_frame *precv_frame)
+{
+	return _rtw_mi_process(padapter, _FALSE, precv_frame, _rtw_mi_report_survey_event);
+}
+
+static u8 _rtw_mi_tx_beacon_hdl(_adapter *adapter, void *data)
+{
+	if (check_fwstate(&adapter->mlmepriv, WIFI_AP_STATE) == _TRUE
+	    && check_fwstate(&adapter->mlmepriv, WIFI_ASOC_STATE) == _TRUE
+	   ) {
+		adapter->mlmepriv.update_bcn = _TRUE;
+	}
+	return _TRUE;
+}
+u8 rtw_mi_tx_beacon_hdl(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_tx_beacon_hdl);
+}
+
+static u8 _rtw_mi_stay_in_p2p_mode(_adapter *adapter, void *data)
+{
+	struct wifidirect_info *pwdinfo = &(adapter->wdinfo);
+
+	if (rtw_p2p_role(pwdinfo) != P2P_ROLE_DISABLE)
+		return _TRUE;
+	return _FALSE;
+}
+u8 rtw_mi_stay_in_p2p_mode(_adapter *padapter)
+{
+	return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_stay_in_p2p_mode);
+}
+
+/*API be created temporary for MI, caller is interrupt-handler, PCIE's interrupt handler cannot apply to multi-AP*/
+_adapter *rtw_mi_get_ap_adapter(_adapter *padapter)
+{
+	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+	int i;
+	_adapter *iface = NULL;
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		iface = dvobj->padapters[i];
+		if (!iface)
+			continue;
+
+		if (check_fwstate(&iface->mlmepriv, WIFI_AP_STATE) == _TRUE
+		    && check_fwstate(&iface->mlmepriv, WIFI_ASOC_STATE) == _TRUE)
+			break;
+
+	}
+	return iface;
+}
diff --git a/drivers/staging/rtl8821ce/core/rtw_mlme.c b/drivers/staging/rtl8821ce/core/rtw_mlme.c
new file mode 100644
index 000000000000..778790acda72
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/rtw_mlme.c
@@ -0,0 +1,3606 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * 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 <hal_data.h>
+
+extern void indicate_wx_scan_complete_event(_adapter *padapter);
+extern u8 rtw_do_join(_adapter *padapter);
+
+void rtw_init_mlme_timer(_adapter *padapter)
+{
+	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+	rtw_init_timer(&(pmlmepriv->assoc_timer), padapter, rtw_join_timeout_handler, padapter);
+	rtw_init_timer(&(pmlmepriv->scan_to_timer), padapter, rtw_scan_timeout_handler, padapter);
+
+
+
+}
+
+sint	_rtw_init_mlme_priv(_adapter *padapter)
+{
+	sint	i;
+	u8	*pbuf;
+	struct wlan_network	*pnetwork;
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	sint	res = _SUCCESS;
+
+	/* We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */
+	/* _rtw_memset((u8 *)pmlmepriv, 0, sizeof(struct mlme_priv)); */
+
+	/*qos_priv*/
+	/*pmlmepriv->qospriv.qos_option = pregistrypriv->wmm_enable;*/
+
+	/*ht_priv*/
+	pmlmepriv->htpriv.ampdu_enable = _FALSE;/*set to disabled*/
+
+	pmlmepriv->nic_hdl = (u8 *)padapter;
+
+	pmlmepriv->pscanned = NULL;
+	/*pmlmepriv->fw_state = WIFI_STATION_STATE; */ /*Must sync with rtw_wdev_alloc()*/
+	/*init_fwstate(pmlmepriv, WIFI_STATION_STATE);*/
+	init_fwstate(pmlmepriv, WIFI_NULL_STATE);/*assigned interface role(STA/AP) must after execute set_opmode*/
+
+	/* wdev->iftype = NL80211_IFTYPE_STATION*/
+	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) */
+
+	_rtw_spinlock_init(&(pmlmepriv->lock));
+	_rtw_init_queue(&(pmlmepriv->free_bss_pool));
+	_rtw_init_queue(&(pmlmepriv->scanned_queue));
+
+	set_scanned_network_val(pmlmepriv, 0);
+
+	_rtw_memset(&pmlmepriv->assoc_ssid, 0, sizeof(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++) {
+		_rtw_init_listhead(&(pnetwork->list));
+
+		rtw_list_insert_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);
+
+#define RTW_ROAM_SCAN_RESULT_EXP_MS (5*1000)
+#define RTW_ROAM_RSSI_DIFF_TH 10
+#define RTW_ROAM_SCAN_INTERVAL_MS (10*1000)
+#define RTW_ROAM_RSSI_THRESHOLD 70
+
+	pmlmepriv->roam_flags = 0
+				| RTW_ROAM_ON_EXPIRED
+				| RTW_ROAM_ON_RESUME
+#ifdef CONFIG_LAYER2_ROAMING_ACTIVE
+				| RTW_ROAM_ACTIVE
+#endif
+				;
+
+	pmlmepriv->roam_scanr_exp_ms = RTW_ROAM_SCAN_RESULT_EXP_MS;
+	pmlmepriv->roam_rssi_diff_th = RTW_ROAM_RSSI_DIFF_TH;
+	pmlmepriv->roam_scan_int_ms = RTW_ROAM_SCAN_INTERVAL_MS;
+	pmlmepriv->roam_rssi_threshold = RTW_ROAM_RSSI_THRESHOLD;
+
+	rtw_init_mlme_timer(padapter);
+
+exit:
+
+	return res;
+}
+
+void rtw_mfree_mlme_priv_lock(struct mlme_priv *pmlmepriv);
+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));
+}
+
+static void rtw_free_mlme_ie_data(u8 **ppie, u32 *plen)
+{
+	if (*ppie) {
+		rtw_mfree(*ppie, *plen);
+		*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);
+	rtw_free_mlme_ie_data(&pmlmepriv->p2p_assoc_resp_ie, &pmlmepriv->p2p_assoc_resp_ie_len);
+
+
+}
+
+
+void _rtw_free_mlme_priv(struct mlme_priv *pmlmepriv)
+{
+	if (NULL == pmlmepriv) {
+		rtw_warn_on(1);
+		goto exit;
+	}
+	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));
+	}
+exit:
+	return;
+}
+
+sint	_rtw_enqueue_network(_queue *queue, struct wlan_network *pnetwork)
+{
+	_irqL irqL;
+
+	if (pnetwork == NULL)
+		goto exit;
+
+	_enter_critical_bh(&queue->lock, &irqL);
+
+	rtw_list_insert_tail(&pnetwork->list, &queue->queue);
+
+	_exit_critical_bh(&queue->lock, &irqL);
+
+exit:
+
+	return _SUCCESS;
+}
+
+/*
+struct	wlan_network *_rtw_dequeue_network(_queue *queue)
+{
+	_irqL irqL;
+
+	struct wlan_network *pnetwork;
+
+	_enter_critical_bh(&queue->lock, &irqL);
+
+	if (_rtw_queue_empty(queue) == _TRUE)
+
+		pnetwork = NULL;
+
+	else
+	{
+		pnetwork = LIST_CONTAINOR(get_next(&queue->queue), struct wlan_network, list);
+
+		rtw_list_delete(&(pnetwork->list));
+	}
+
+	_exit_critical_bh(&queue->lock, &irqL);
+
+	return pnetwork;
+}
+*/
+
+struct	wlan_network *_rtw_alloc_network(struct	mlme_priv *pmlmepriv) /* (_queue *free_queue) */
+{
+	_irqL	irqL;
+	struct	wlan_network	*pnetwork;
+	_queue *free_queue = &pmlmepriv->free_bss_pool;
+	_list *plist = NULL;
+
+	_enter_critical_bh(&free_queue->lock, &irqL);
+
+	if (_rtw_queue_empty(free_queue) == _TRUE) {
+		pnetwork = NULL;
+		goto exit;
+	}
+	plist = get_next(&(free_queue->queue));
+
+	pnetwork = LIST_CONTAINOR(plist , struct wlan_network, list);
+
+	rtw_list_delete(&pnetwork->list);
+
+	pnetwork->network_type = 0;
+	pnetwork->fixed = _FALSE;
+	pnetwork->last_scanned = rtw_get_current_time();
+	pnetwork->aid = 0;
+	pnetwork->join_res = 0;
+
+	pmlmepriv->num_of_scanned++;
+
+exit:
+	_exit_critical_bh(&free_queue->lock, &irqL);
+
+	return pnetwork;
+}
+
+void _rtw_free_network(struct	mlme_priv *pmlmepriv , struct wlan_network *pnetwork, u8 isfreeall)
+{
+	u32 delta_time;
+	u32 lifetime = SCANQUEUE_LIFETIME;
+	_irqL irqL;
+	_queue *free_queue = &(pmlmepriv->free_bss_pool);
+
+	if (pnetwork == NULL)
+		goto exit;
+
+	if (pnetwork->fixed == _TRUE)
+		goto exit;
+
+	if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) ||
+	    (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE))
+		lifetime = 1;
+
+	if (!isfreeall) {
+		delta_time = (u32) rtw_get_passing_time_ms(pnetwork->last_scanned);
+		if (delta_time < lifetime) /* unit:msec */
+			goto exit;
+	}
+
+	_enter_critical_bh(&free_queue->lock, &irqL);
+
+	rtw_list_delete(&(pnetwork->list));
+
+	rtw_list_insert_tail(&(pnetwork->list), &(free_queue->queue));
+
+	pmlmepriv->num_of_scanned--;
+
+	/* RTW_INFO("_rtw_free_network:SSID=%s\n", pnetwork->network.Ssid.Ssid); */
+
+	_exit_critical_bh(&free_queue->lock, &irqL);
+
+exit:
+	return;
+}
+
+void _rtw_free_network_nolock(struct	mlme_priv *pmlmepriv, struct wlan_network *pnetwork)
+{
+
+	_queue *free_queue = &(pmlmepriv->free_bss_pool);
+
+	if (pnetwork == NULL)
+		goto exit;
+
+	if (pnetwork->fixed == _TRUE)
+		goto exit;
+
+	/* _enter_critical(&free_queue->lock, &irqL); */
+
+	rtw_list_delete(&(pnetwork->list));
+
+	rtw_list_insert_tail(&(pnetwork->list), get_list_head(free_queue));
+
+	pmlmepriv->num_of_scanned--;
+
+	/* _exit_critical(&free_queue->lock, &irqL); */
+
+exit:
+	return;
+}
+
+/*
+	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(_queue *scanned_queue, u8 *addr)
+{
+
+	/* _irqL irqL; */
+	_list	*phead, *plist;
+	struct	wlan_network *pnetwork = NULL;
+	u8 zero_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
+
+	if (_rtw_memcmp(zero_addr, addr, ETH_ALEN)) {
+		pnetwork = NULL;
+		goto exit;
+	}
+
+	/* _enter_critical_bh(&scanned_queue->lock, &irqL); */
+
+	phead = get_list_head(scanned_queue);
+	plist = get_next(phead);
+
+	while (plist != phead) {
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network , list);
+
+		if (_rtw_memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN) == _TRUE)
+			break;
+
+		plist = get_next(plist);
+	}
+
+	if (plist == phead)
+		pnetwork = NULL;
+
+	/* _exit_critical_bh(&scanned_queue->lock, &irqL); */
+
+exit:
+
+	return pnetwork;
+
+}
+
+void _rtw_free_network_queue(_adapter *padapter, u8 isfreeall)
+{
+	_irqL irqL;
+	_list *phead, *plist;
+	struct wlan_network *pnetwork;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	_queue *scanned_queue = &pmlmepriv->scanned_queue;
+
+	_enter_critical_bh(&scanned_queue->lock, &irqL);
+
+	phead = get_list_head(scanned_queue);
+	plist = get_next(phead);
+
+	while (rtw_end_of_queue_search(phead, plist) == _FALSE) {
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+		plist = get_next(plist);
+
+		_rtw_free_network(pmlmepriv, pnetwork, isfreeall);
+
+	}
+
+	_exit_critical_bh(&scanned_queue->lock, &irqL);
+
+}
+
+sint rtw_if_up(_adapter *padapter)
+{
+
+	sint res;
+
+	if (RTW_CANNOT_RUN(padapter) ||
+	    (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == _FALSE)) {
+		res = _FALSE;
+	} else
+		res =  _TRUE;
+
+	return res;
+}
+
+void rtw_generate_random_ibss(u8 *pibss)
+{
+	*((u32 *)(&pibss[2])) = rtw_random32();
+	pibss[0] = 0x02; /* in ad-hoc mode local bit must set to 1 */
+	pibss[1] = 0x11;
+	pibss[2] = 0x87;
+}
+
+u8 *rtw_get_capability_from_ie(u8 *ie)
+{
+	return ie + 8 + 2;
+}
+
+u16 rtw_get_capability(WLAN_BSSID_EX *bss)
+{
+	u16	val;
+
+	_rtw_memcpy((u8 *)&val, rtw_get_capability_from_ie(bss->IEs), 2);
+
+	return le16_to_cpu(val);
+}
+
+u8 *rtw_get_beacon_interval_from_ie(u8 *ie)
+{
+	return ie + 8;
+}
+
+int	rtw_init_mlme_priv(_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)
+{
+	_rtw_free_mlme_priv(pmlmepriv);
+}
+
+/*
+static struct	wlan_network *rtw_dequeue_network(_queue *queue)
+{
+	struct wlan_network *pnetwork;
+	pnetwork = _rtw_dequeue_network(queue);
+	return pnetwork;
+}
+*/
+
+struct	wlan_network *rtw_alloc_network(struct	mlme_priv *pmlmepriv);
+struct	wlan_network *rtw_alloc_network(struct	mlme_priv *pmlmepriv) /* (_queue	*free_queue) */
+{
+	struct	wlan_network	*pnetwork;
+	pnetwork = _rtw_alloc_network(pmlmepriv);
+	return pnetwork;
+}
+
+void rtw_free_network_nolock(_adapter *padapter, struct wlan_network *pnetwork);
+void rtw_free_network_nolock(_adapter *padapter, struct wlan_network *pnetwork)
+{
+	_rtw_free_network_nolock(&(padapter->mlmepriv), pnetwork);
+}
+
+void rtw_free_network_queue(_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(_queue *scanned_queue, u8 *addr)
+{
+	struct	wlan_network *pnetwork = _rtw_find_network(scanned_queue, addr);
+
+	return pnetwork;
+}
+
+int rtw_is_same_ibss(_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;
+
+}
+
+inline int is_same_ess(WLAN_BSSID_EX *a, WLAN_BSSID_EX *b)
+{
+	return (a->Ssid.SsidLength == b->Ssid.SsidLength)
+	       &&  _rtw_memcmp(a->Ssid.Ssid, b->Ssid.Ssid, a->Ssid.SsidLength) == _TRUE;
+}
+
+int is_same_network(WLAN_BSSID_EX *src, WLAN_BSSID_EX *dst, u8 feature)
+{
+	u16 s_cap, d_cap;
+
+	if (rtw_bug_check(dst, src, &s_cap, &d_cap) == _FALSE)
+		return _FALSE;
+
+	_rtw_memcpy((u8 *)&s_cap, rtw_get_capability_from_ie(src->IEs), 2);
+	_rtw_memcpy((u8 *)&d_cap, rtw_get_capability_from_ie(dst->IEs), 2);
+
+	s_cap = le16_to_cpu(s_cap);
+	d_cap = le16_to_cpu(d_cap);
+
+	if ((feature == 1) && /* 1: P2P supported */
+	    (_rtw_memcmp(src->MacAddress, dst->MacAddress, ETH_ALEN) == _TRUE)
+	   )
+		return _TRUE;
+
+	return ((src->Ssid.SsidLength == dst->Ssid.SsidLength) &&
+		/*	(src->Configuration.DSConfig == dst->Configuration.DSConfig) && */
+		((_rtw_memcmp(src->MacAddress, dst->MacAddress, ETH_ALEN)) == _TRUE) &&
+		((_rtw_memcmp(src->Ssid.Ssid, dst->Ssid.Ssid, src->Ssid.SsidLength)) == _TRUE) &&
+		((s_cap & WLAN_CAPABILITY_IBSS) ==
+		 (d_cap & WLAN_CAPABILITY_IBSS)) &&
+		((s_cap & WLAN_CAPABILITY_BSS) ==
+		 (d_cap & WLAN_CAPABILITY_BSS)));
+
+}
+
+struct wlan_network *_rtw_find_same_network(_queue *scanned_queue, struct wlan_network *network)
+{
+	_list *phead, *plist;
+	struct wlan_network *found = NULL;
+
+	phead = get_list_head(scanned_queue);
+	plist = get_next(phead);
+
+	while (plist != phead) {
+		found = LIST_CONTAINOR(plist, struct wlan_network , list);
+
+		if (is_same_network(&network->network, &found->network, 0))
+			break;
+
+		plist = get_next(plist);
+	}
+
+	if (plist == phead)
+		found = NULL;
+
+	return found;
+}
+
+struct	wlan_network	*rtw_get_oldest_wlan_network(_queue *scanned_queue)
+{
+	_list	*plist, *phead;
+
+	struct	wlan_network	*pwlan = NULL;
+	struct	wlan_network	*oldest = NULL;
+	phead = get_list_head(scanned_queue);
+
+	plist = get_next(phead);
+
+	while (1) {
+
+		if (rtw_end_of_queue_search(phead, plist) == _TRUE)
+			break;
+
+		pwlan = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+		if (pwlan->fixed != _TRUE) {
+			if (oldest == NULL || time_after(oldest->last_scanned, pwlan->last_scanned))
+				oldest = pwlan;
+		}
+
+		plist = get_next(plist);
+	}
+	return oldest;
+
+}
+
+void update_network(WLAN_BSSID_EX *dst, WLAN_BSSID_EX *src,
+		    _adapter *padapter, bool update_ie)
+{
+	u8 ss_ori = dst->PhyInfo.SignalStrength;
+	u8 sq_ori = dst->PhyInfo.SignalQuality;
+	long rssi_ori = dst->Rssi;
+
+	u8 ss_smp = src->PhyInfo.SignalStrength;
+	u8 sq_smp = src->PhyInfo.SignalQuality;
+	long rssi_smp = src->Rssi;
+
+	u8 ss_final;
+	u8 sq_final;
+	long rssi_final;
+
+
+
+	/* 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, 0)) {
+		/* 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 = (src->Rssi + dst->Rssi * 4) / 5;
+		else
+			rssi_final = rssi_ori;
+	} else {
+		if (sq_smp != 101) { /* from the right channel */
+			ss_final = ((u32)(src->PhyInfo.SignalStrength) + (u32)(dst->PhyInfo.SignalStrength) * 4) / 5;
+			sq_final = ((u32)(src->PhyInfo.SignalQuality) + (u32)(dst->PhyInfo.SignalQuality) * 4) / 5;
+			rssi_final = (src->Rssi + dst->Rssi * 4) / 5;
+		} else {
+			/* bss info not receving 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];
+		_rtw_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(_adapter *adapter, WLAN_BSSID_EX *pnetwork)
+{
+	struct	mlme_priv	*pmlmepriv = &(adapter->mlmepriv);
+
+	rtw_bug_check(&(pmlmepriv->cur_network.network),
+		      &(pmlmepriv->cur_network.network),
+		      &(pmlmepriv->cur_network.network),
+		      &(pmlmepriv->cur_network.network));
+
+	if ((check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) && (is_same_network(&(pmlmepriv->cur_network.network), pnetwork, 0))) {
+
+		/* if(pmlmepriv->cur_network.network.IELength<= pnetwork->IELength) */
+		{
+			update_network(&(pmlmepriv->cur_network.network), pnetwork, adapter, _TRUE);
+			rtw_update_protection(adapter, (pmlmepriv->cur_network.network.IEs) + sizeof(NDIS_802_11_FIXED_IEs),
+				      pmlmepriv->cur_network.network.IELength);
+		}
+	}
+
+}
+
+/*
+
+Caller must hold pmlmepriv->lock first.
+
+*/
+void rtw_update_scanned_network(_adapter *adapter, WLAN_BSSID_EX *target)
+{
+	_irqL irqL;
+	_list	*plist, *phead;
+	ULONG	bssid_ex_sz;
+	struct mlme_priv	*pmlmepriv = &(adapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(adapter->mlmeextpriv);
+	struct wifidirect_info *pwdinfo = &(adapter->wdinfo);
+	_queue	*queue	= &(pmlmepriv->scanned_queue);
+	struct wlan_network	*pnetwork = NULL;
+	struct wlan_network	*oldest = NULL;
+	int target_find = 0;
+	u8 feature = 0;
+
+	_enter_critical_bh(&queue->lock, &irqL);
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+		feature = 1; /* p2p enable */
+
+	while (1) {
+		if (rtw_end_of_queue_search(phead, plist) == _TRUE)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+		rtw_bug_check(pnetwork, pnetwork, pnetwork, pnetwork);
+
+		if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) &&
+		    (_rtw_memcmp(pnetwork->network.MacAddress, target->MacAddress, ETH_ALEN) == _TRUE)) {
+			target_find = 1;
+			break;
+		}
+
+		if (is_same_network(&(pnetwork->network), target, feature)) {
+			target_find = 1;
+			break;
+		}
+
+		if (rtw_roam_flags(adapter)) {
+			/* TODO: don't  select netowrk in the same ess as oldest if it's new enough*/
+		}
+#ifdef CONFIG_RSSI_PRIORITY
+		if ((oldest == NULL) || (pnetwork->network.PhyInfo.SignalStrength < oldest->network.PhyInfo.SignalStrength))
+			oldest = pnetwork;
+#else
+		if (oldest == NULL || time_after(oldest->last_scanned, pnetwork->last_scanned))
+			oldest = pnetwork;
+#endif
+		plist = get_next(plist);
+
+	}
+
+	/* If we didn't find a match, then get a new network slot to initialize
+	 * with this beacon's information */
+	/* if (rtw_end_of_queue_search(phead,plist)== _TRUE) { */
+	if (!target_find) {
+		if (_rtw_queue_empty(&(pmlmepriv->free_bss_pool)) == _TRUE) {
+			/* If there are no more slots, expire the oldest */
+			/* list_del_init(&oldest->list); */
+			pnetwork = oldest;
+			if (pnetwork == NULL) {
+				goto exit;
+			}
+#ifdef CONFIG_RSSI_PRIORITY
+		RTW_DBG("%s => ssid:%s ,bssid:"MAC_FMT"  will be deleted from scanned_queue (rssi:%ld , ss:%d)\n",
+			__func__, pnetwork->network.Ssid.Ssid, MAC_ARG(pnetwork->network.MacAddress), pnetwork->network.Rssi, pnetwork->network.PhyInfo.SignalStrength);
+#else
+		RTW_DBG("%s => ssid:%s ,bssid:"MAC_FMT" will be deleted from scanned_queue\n",
+			__func__, pnetwork->network.Ssid.Ssid, MAC_ARG(pnetwork->network.MacAddress));
+#endif
+
+			_rtw_memcpy(&(pnetwork->network), target,  get_WLAN_BSSID_EX_sz(target));
+			/* pnetwork->last_scanned = rtw_get_current_time(); */
+			/* variable initialize */
+			pnetwork->fixed = _FALSE;
+			pnetwork->last_scanned = rtw_get_current_time();
+
+			pnetwork->network_type = 0;
+			pnetwork->aid = 0;
+			pnetwork->join_res = 0;
+
+			/* bss info not receving 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) {
+				goto exit;
+			}
+
+			bssid_ex_sz = get_WLAN_BSSID_EX_sz(target);
+			target->Length = bssid_ex_sz;
+			_rtw_memcpy(&(pnetwork->network), target, bssid_ex_sz);
+
+			pnetwork->last_scanned = rtw_get_current_time();
+
+			/* bss info not receving from the right channel */
+			if (pnetwork->network.PhyInfo.SignalQuality == 101)
+				pnetwork->network.PhyInfo.SignalQuality = 0;
+
+			rtw_list_insert_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 = rtw_get_current_time();
+
+		/* target.Reserved[0]==1, means that scaned network is a bcn frame. */
+		if ((pnetwork->network.IELength > target->IELength) && (target->Reserved[0] == 1))
+			update_ie = _FALSE;
+
+		/* 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:
+	_exit_critical_bh(&queue->lock, &irqL);
+
+}
+
+void rtw_add_network(_adapter *adapter, WLAN_BSSID_EX *pnetwork);
+void rtw_add_network(_adapter *adapter, WLAN_BSSID_EX *pnetwork)
+{
+	_irqL irqL;
+	struct	mlme_priv	*pmlmepriv = &(((_adapter *)adapter)->mlmepriv);
+	/* _queue	*queue	= &(pmlmepriv->scanned_queue); */
+
+	/* _enter_critical_bh(&queue->lock, &irqL); */
+
+	if (adapter->registrypriv.wifi_spec == 0)
+		rtw_bss_ex_del_p2p_attr(pnetwork, P2P_ATTR_GROUP_INFO);
+
+	if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST))
+		rtw_bss_ex_del_wfd_ie(pnetwork);
+
+	update_current_network(adapter, pnetwork);
+
+	rtw_update_scanned_network(adapter, pnetwork);
+
+	/* _exit_critical_bh(&queue->lock, &irqL); */
+
+}
+
+/* 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 */
+int rtw_is_desired_network(_adapter *adapter, struct wlan_network *pnetwork);
+int rtw_is_desired_network(_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)) {
+		RTW_INFO("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(_adapter	*adapter , u8 *pbuf)
+{
+
+	return;
+}
+
+void rtw_survey_event_callback(_adapter	*adapter, u8 *pbuf)
+{
+	_irqL  irqL;
+	u32 len;
+	WLAN_BSSID_EX *pnetwork;
+	struct	mlme_priv	*pmlmepriv = &(adapter->mlmepriv);
+
+	pnetwork = (WLAN_BSSID_EX *)pbuf;
+
+	len = get_WLAN_BSSID_EX_sz(pnetwork);
+	if (len > (sizeof(WLAN_BSSID_EX))) {
+		return;
+	}
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	/* update IBSS_network 's timestamp */
+	if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == _TRUE) {
+		if (_rtw_memcmp(&(pmlmepriv->cur_network.network.MacAddress), pnetwork->MacAddress, ETH_ALEN)) {
+			struct wlan_network *ibss_wlan = NULL;
+			_irqL	irqL;
+
+			_rtw_memcpy(pmlmepriv->cur_network.network.IEs, pnetwork->IEs, 8);
+			_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+			ibss_wlan = rtw_find_network(&pmlmepriv->scanned_queue,  pnetwork->MacAddress);
+			if (ibss_wlan) {
+				_rtw_memcpy(ibss_wlan->network.IEs , pnetwork->IEs, 8);
+				_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+				goto exit;
+			}
+			_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+		}
+	}
+
+	/* 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:
+
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+	return;
+}
+
+void rtw_surveydone_event_callback(_adapter	*adapter, u8 *pbuf)
+{
+	_irqL  irqL;
+	struct	mlme_priv	*pmlmepriv = &(adapter->mlmepriv);
+
+#ifdef CONFIG_MLME_EXT
+	mlmeext_surveydone_event_callback(adapter);
+#endif
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+	if (pmlmepriv->wps_probe_req_ie) {
+		u32 free_len = pmlmepriv->wps_probe_req_ie_len;
+		pmlmepriv->wps_probe_req_ie_len = 0;
+		rtw_mfree(pmlmepriv->wps_probe_req_ie, free_len);
+		pmlmepriv->wps_probe_req_ie = NULL;
+	}
+
+	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _FALSE) {
+		RTW_INFO(FUNC_ADPT_FMT" fw_state:0x%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv));
+		/* rtw_warn_on(1); */
+	}
+
+	_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+	_cancel_timer_ex(&pmlmepriv->scan_to_timer);
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	rtw_set_signal_stat_timer(&adapter->recvpriv);
+
+	if (pmlmepriv->to_join == _TRUE) {
+		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 {
+					WLAN_BSSID_EX    *pdev_network = &(adapter->registrypriv.dev_network);
+					u8 *pibss = adapter->registrypriv.dev_network.MacAddress;
+
+					/* pmlmepriv->fw_state ^= _FW_UNDER_SURVEY; */ /* because don't set assoc_timer */
+					_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+
+					_rtw_memset(&pdev_network->Ssid, 0, sizeof(NDIS_802_11_SSID));
+					_rtw_memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(NDIS_802_11_SSID));
+
+					rtw_update_registrypriv_dev_network(adapter);
+					rtw_generate_random_ibss(pibss);
+
+					/*pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;*/
+					init_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
+
+					if (rtw_create_ibss_cmd(adapter, 0) != _SUCCESS)
+						RTW_ERR("rtw_create_ibss_cmd 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 {
+				RTW_INFO("try_to_join, but select scanning queue fail, to_roam:%d\n", rtw_to_roam(adapter));
+
+				if (rtw_to_roam(adapter) != 0) {
+					if (rtw_dec_to_roam(adapter) == 0
+					    || _SUCCESS != rtw_sitesurvey_cmd(adapter, &pmlmepriv->assoc_ssid, 1, NULL, 0)
+					   ) {
+						rtw_set_to_roam(adapter, 0);
+						rtw_free_assoc_resources(adapter, 1);
+						rtw_indicate_disconnect(adapter, 0, _FALSE);
+					} else
+						pmlmepriv->to_join = _TRUE;
+				} else
+					rtw_indicate_disconnect(adapter, 0, _FALSE);
+				_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+			}
+		}
+	} else {
+		if (rtw_chk_roam_flags(adapter, RTW_ROAM_ACTIVE)) {
+			if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)
+			    && check_fwstate(pmlmepriv, _FW_LINKED)) {
+				if (rtw_select_roaming_candidate(pmlmepriv) == _SUCCESS) {
+					receive_disconnect(adapter, pmlmepriv->cur_network.network.MacAddress
+						, WLAN_REASON_ACTIVE_ROAM, _FALSE);
+				}
+			}
+		}
+	}
+
+	/* RTW_INFO("scan complete in %dms\n",rtw_get_passing_time_ms(pmlmepriv->scan_start_time)); */
+
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
+		p2p_ps_wk_cmd(adapter, P2P_PS_SCAN_DONE, 0);
+
+	rtw_mi_os_xmit_schedule(adapter);
+
+#ifdef CONFIG_DRVEXT_MODULE_WSC
+	drvext_surveydone_callback(&adapter->drvextpriv);
+#endif
+
+	{
+		struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+		if (pmlmeext->sitesurvey_res.bss_cnt == 0) {
+			/* rtw_hal_sreset_reset(adapter); */
+		}
+	}
+
+
+	rtw_indicate_scan_done(adapter, _FALSE);
+
+
+}
+
+void rtw_dummy_event_callback(_adapter *adapter , u8 *pbuf)
+{
+
+}
+
+void rtw_fwdbg_event_callback(_adapter *adapter , u8 *pbuf)
+{
+
+}
+
+static void free_scanqueue(struct	mlme_priv *pmlmepriv)
+{
+	_irqL irqL, irqL0;
+	_queue *free_queue = &pmlmepriv->free_bss_pool;
+	_queue *scan_queue = &pmlmepriv->scanned_queue;
+	_list	*plist, *phead, *ptemp;
+
+	_enter_critical_bh(&scan_queue->lock, &irqL0);
+	_enter_critical_bh(&free_queue->lock, &irqL);
+
+	phead = get_list_head(scan_queue);
+	plist = get_next(phead);
+
+	while (plist != phead) {
+		ptemp = get_next(plist);
+		rtw_list_delete(plist);
+		rtw_list_insert_tail(plist, &free_queue->queue);
+		plist = ptemp;
+		pmlmepriv->num_of_scanned--;
+	}
+
+	_exit_critical_bh(&free_queue->lock, &irqL);
+	_exit_critical_bh(&scan_queue->lock, &irqL0);
+
+}
+
+void rtw_reset_rx_info(struct debug_priv *pdbgpriv)
+{
+	pdbgpriv->dbg_rx_ampdu_drop_count = 0;
+	pdbgpriv->dbg_rx_ampdu_forced_indicate_count = 0;
+	pdbgpriv->dbg_rx_ampdu_loss_count = 0;
+	pdbgpriv->dbg_rx_dup_mgt_frame_drop_count = 0;
+	pdbgpriv->dbg_rx_ampdu_window_shift_cnt = 0;
+}
+
+/*
+*rtw_free_assoc_resources: the caller has to lock pmlmepriv->lock
+*/
+void rtw_free_assoc_resources(_adapter *adapter, int lock_scanned_queue)
+{
+	_irqL irqL;
+	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;
+	struct dvobj_priv *psdpriv = adapter->dvobj;
+	struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
+
+	RTW_INFO("%s-"ADPT_FMT" tgt_network MacAddress=" MAC_FMT"ssid=%s\n",
+		__func__, ADPT_ARG(adapter), MAC_ARG(tgt_network->network.MacAddress), tgt_network->network.Ssid.Ssid);
+
+	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+		struct sta_info *psta;
+
+		psta = rtw_get_stainfo(&adapter->stapriv, tgt_network->network.MacAddress);
+
+		{
+			/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
+			rtw_free_stainfo(adapter,  psta);
+		}
+
+		/* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
+
+	}
+
+	if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) {
+		struct sta_info *psta;
+
+		rtw_free_all_stainfo(adapter);
+
+		psta = rtw_get_bcmc_stainfo(adapter);
+		/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);		 */
+		rtw_free_stainfo(adapter, psta);
+		/* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);		 */
+
+		rtw_init_bcmc_stainfo(adapter);
+	}
+
+	if (lock_scanned_queue)
+		_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	pwlan = _rtw_find_same_network(&pmlmepriv->scanned_queue, tgt_network);
+	if ((pwlan)  && (!check_fwstate(pmlmepriv, WIFI_UNDER_WPS))) {
+		pwlan->fixed = _FALSE;
+
+		RTW_INFO("free disconnecting network of scanned_queue\n");
+		rtw_free_network_nolock(adapter, pwlan);
+		if (!rtw_p2p_chk_state(&adapter->wdinfo, P2P_STATE_NONE)) {
+			rtw_mi_set_scan_deny(adapter, 2000);
+			/* rtw_clear_scan_deny(adapter);			 */
+		}
+	} else {
+		if (pwlan == NULL)
+			RTW_INFO("free disconnecting network of scanned_queue failed due to pwlan== NULL\n\n");
+		if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS))
+			RTW_INFO("donot free disconnecting network of scanned_queue when WIFI_UNDER_WPS\n\n");
+	}
+
+	if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && (adapter->stapriv.asoc_sta_count == 1))
+	    /*||check_fwstate(pmlmepriv, WIFI_STATION_STATE)*/) {
+		if (pwlan)
+			rtw_free_network_nolock(adapter, pwlan);
+	}
+
+	if (lock_scanned_queue)
+		_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	adapter->securitypriv.key_mask = 0;
+
+	rtw_reset_rx_info(pdbgpriv);
+
+}
+
+/*
+*rtw_indicate_connect: the caller has to lock pmlmepriv->lock
+*/
+void rtw_indicate_connect(_adapter *padapter)
+{
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct xmit_priv	*pxmitpriv = &padapter->xmitpriv;
+
+	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);
+		}
+
+	}
+
+	rtw_set_to_roam(padapter, 0);
+	if (!check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE))
+		rtw_mi_set_scan_deny(padapter, 3000);
+
+}
+
+/*
+*rtw_indicate_disconnect: the caller has to lock pmlmepriv->lock
+*/
+void rtw_indicate_disconnect(_adapter *padapter, u16 reason, u8 locally_generated)
+{
+	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX	*cur_network = &(pmlmeinfo->network);
+	struct sta_info *psta;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 *wps_ie = NULL;
+	uint wpsie_len = 0;
+
+	_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING | WIFI_UNDER_WPS);
+
+	/* force to clear cur_network_scanned's SELECTED REGISTRAR */
+	if (pmlmepriv->cur_network_scanned) {
+		WLAN_BSSID_EX	*current_joined_bss = &(pmlmepriv->cur_network_scanned->network);
+		if (current_joined_bss) {
+			wps_ie = rtw_get_wps_ie(current_joined_bss->IEs + _FIXED_IE_LENGTH_,
+				current_joined_bss->IELength - _FIXED_IE_LENGTH_, NULL, &wpsie_len);
+			if (wps_ie && wpsie_len > 0) {
+				u8 *attr = NULL;
+				u32 attr_len;
+				attr = rtw_get_wps_attr(wps_ie, wpsie_len, WPS_ATTR_SELECTED_REGISTRAR,
+							NULL, &attr_len);
+				if (attr)
+					*(attr + 4) = 0;
+			}
+		}
+	}
+	/* RTW_INFO("clear wps when %s\n", __func__); */
+
+	if (rtw_to_roam(padapter) > 0)
+		_clr_fwstate_(pmlmepriv, _FW_LINKED);
+
+	if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)
+	    || (rtw_to_roam(padapter) <= 0)
+	   ) {
+
+		rtw_os_indicate_disconnect(padapter, reason, locally_generated);
+
+		/* set ips_deny_time to avoid enter IPS before LPS leave */
+		rtw_set_ips_deny(padapter, 3000);
+
+		_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(_adapter *padapter, bool aborted)
+{
+	RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
+
+	rtw_os_indicate_scan_done(padapter, aborted);
+
+	if (is_primary_adapter(padapter)
+	    && (_FALSE == adapter_to_pwrctl(padapter)->bInSuspend)
+	    && (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE | WIFI_UNDER_LINKING) == _FALSE)) {
+		struct pwrctrl_priv *pwrpriv;
+
+		pwrpriv = adapter_to_pwrctl(padapter);
+		rtw_set_ips_deny(padapter, 0);
+#ifdef CONFIG_IPS_CHECK_IN_WD
+		_set_timer(&adapter_to_dvobj(padapter)->dynamic_chk_timer, 1);
+#else /* !CONFIG_IPS_CHECK_IN_WD */
+		_rtw_set_pwr_state_check_timer(pwrpriv, 1);
+#endif /* !CONFIG_IPS_CHECK_IN_WD */
+	}
+}
+
+static u32 _rtw_wait_scan_done(_adapter *adapter, u8 abort, u32 timeout_ms)
+{
+	u32 start;
+	u32 pass_ms;
+	struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv);
+
+	start = rtw_get_current_time();
+
+	pmlmeext->scan_abort = abort;
+
+	while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)
+	       && rtw_get_passing_time_ms(start) <= timeout_ms) {
+
+		if (RTW_CANNOT_RUN(adapter))
+			break;
+
+		RTW_INFO(FUNC_NDEV_FMT"fw_state=_FW_UNDER_SURVEY!\n", FUNC_NDEV_ARG(adapter->pnetdev));
+		rtw_msleep_os(20);
+	}
+
+	if (_TRUE == abort) {
+		if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
+			if (!RTW_CANNOT_RUN(adapter))
+				RTW_INFO(FUNC_NDEV_FMT"waiting for scan_abort time out!\n", FUNC_NDEV_ARG(adapter->pnetdev));
+#ifdef CONFIG_PLATFORM_MSTAR
+			/*_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);*/
+			set_survey_timer(pmlmeext, 0);
+			mlme_set_scan_to_timer(pmlmepriv, 50);
+#endif
+			rtw_indicate_scan_done(adapter, _TRUE);
+		}
+	}
+
+	pmlmeext->scan_abort = _FALSE;
+	pass_ms = rtw_get_passing_time_ms(start);
+
+	return pass_ms;
+
+}
+
+void rtw_scan_wait_completed(_adapter *adapter)
+{
+	u32 scan_to = SCANNING_TIMEOUT;
+
+
+	_rtw_wait_scan_done(adapter, _FALSE, scan_to);
+}
+
+u32 rtw_scan_abort_timeout(_adapter *adapter, u32 timeout_ms)
+{
+	return _rtw_wait_scan_done(adapter, _TRUE, timeout_ms);
+}
+
+void rtw_scan_abort_no_wait(_adapter *adapter)
+{
+	struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv);
+
+	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
+		pmlmeext->scan_abort = _TRUE;
+}
+
+void rtw_scan_abort(_adapter *adapter)
+{
+	rtw_scan_abort_timeout(adapter, 200);
+}
+
+static struct sta_info *rtw_joinbss_update_stainfo(_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;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+
+	psta = rtw_get_stainfo(pstapriv, pnetwork->network.MacAddress);
+	if (psta == NULL)
+		psta = rtw_alloc_stainfo(pstapriv, pnetwork->network.MacAddress);
+
+	if (psta) { /* update ptarget_sta */
+		RTW_INFO("%s\n", __FUNCTION__);
+
+		psta->aid  = pnetwork->join_res;
+
+		update_sta_info(padapter, psta);
+
+		/* update station supportRate */
+		psta->bssratelen = rtw_get_rateset_len(pnetwork->network.SupportedRates);
+		_rtw_memcpy(psta->bssrateset, pnetwork->network.SupportedRates, psta->bssratelen);
+		rtw_hal_update_sta_rate_mask(padapter, psta);
+
+		psta->wireless_mode = pmlmeext->cur_wireless_mode;
+		psta->raid = rtw_hal_networktype_to_raid(padapter, psta);
+
+		/* 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;
+
+			_rtw_memset((u8 *)&psta->dot118021x_UncstKey, 0, sizeof(union Keytype));
+
+			_rtw_memset((u8 *)&psta->dot11tkiprxmickey, 0, sizeof(union Keytype));
+			_rtw_memset((u8 *)&psta->dot11tkiptxmickey, 0, sizeof(union Keytype));
+
+			_rtw_memset((u8 *)&psta->dot11txpn, 0, sizeof(union pn48));
+			psta->dot11txpn.val = psta->dot11txpn.val + 1;
+			_rtw_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, reseting  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 */
+			preorder_ctrl->ampdu_size = RX_AMPDU_SIZE_INVALID;
+		}
+
+		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 */
+				preorder_ctrl->ampdu_size = RX_AMPDU_SIZE_INVALID;
+			}
+		}
+	}
+
+	return psta;
+
+}
+
+/* pnetwork : returns from rtw_joinbss_event_callback
+ * ptarget_wlan: found from scanned_queue */
+static void rtw_joinbss_update_network(_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);
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	/* why not use ptarget_wlan?? */
+	_rtw_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;
+	_rtw_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;*/
+			init_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_UNDER_WPS);
+		else
+			/*pmlmepriv->fw_state = WIFI_STATION_STATE;*/
+			init_fwstate(pmlmepriv, WIFI_STATION_STATE);
+		break;
+	case Ndis802_11IBSS:
+		/*pmlmepriv->fw_state = WIFI_ADHOC_STATE;*/
+		init_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+		break;
+	default:
+		/*pmlmepriv->fw_state = WIFI_NULL_STATE;*/
+		init_fwstate(pmlmepriv, WIFI_NULL_STATE);
+		break;
+	}
+
+	rtw_update_protection(padapter, (cur_network->network.IEs) + sizeof(NDIS_802_11_FIXED_IEs),
+			      (cur_network->network.IELength));
+
+	rtw_update_ht_cap(padapter, cur_network->network.IEs, cur_network->network.IELength, (u8) cur_network->network.Configuration.DSConfig);
+}
+
+/* Notes: the fucntion 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).
+ */
+/* #define REJOIN */
+void rtw_joinbss_event_prehandle(_adapter *adapter, u8 *pbuf)
+{
+	_irqL irqL, irqL2;
+	static u8 retry = 0;
+	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;
+
+	rtw_get_encrypt_decrypt_from_registrypriv(adapter);
+
+	the_same_macaddr = _rtw_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(WLAN_BSSID_EX)) {
+		goto ignore_joinbss_callback;
+	}
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0;
+	pmlmepriv->LinkDetectInfo.LowPowerTransitionCount = 0;
+
+	if (pnetwork->join_res > 0) {
+		_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+		retry = 0;
+		if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) {
+			/* s1. find ptarget_wlan */
+			if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+				if (the_same_macaddr == _TRUE)
+					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) {
+						/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); */
+						rtw_free_stainfo(adapter,  pcur_sta);
+						/* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); */
+					}
+
+					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_same_network(&pmlmepriv->scanned_queue, pnetwork);
+				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 {
+				RTW_PRINT("Can't find ptarget_wlan when joinbss_event callback\n");
+				_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+				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) {
+					RTW_ERR("Can't update stainfo when joinbss_event callback\n");
+					_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+					goto ignore_joinbss_callback;
+				}
+			}
+
+			/* s4. indicate connect			 */
+			if (MLME_IS_STA(adapter) || MLME_IS_ADHOC(adapter)) {
+				pmlmepriv->cur_network_scanned = ptarget_wlan;
+				rtw_indicate_connect(adapter);
+			}
+
+			/* s5. Cancle assoc_timer					 */
+			_cancel_timer_ex(&pmlmepriv->assoc_timer);
+
+		} else {
+			_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+			goto ignore_joinbss_callback;
+		}
+
+		_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	} else if (pnetwork->join_res == -4) {
+		rtw_reset_securitypriv(adapter);
+		_set_timer(&pmlmepriv->assoc_timer, 1);
+
+		/* rtw_free_assoc_resources(adapter, 1); */
+
+		if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == _TRUE) {
+			_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+		}
+
+	} else { /* if join_res < 0 (join fails), then try again */
+
+
+			_set_timer(&pmlmepriv->assoc_timer, 1);
+			/* rtw_free_assoc_resources(adapter, 1); */
+			_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+	}
+
+ignore_joinbss_callback:
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+}
+
+void rtw_joinbss_event_callback(_adapter *adapter, u8 *pbuf)
+{
+	struct wlan_network	*pnetwork	= (struct wlan_network *)pbuf;
+
+	mlmeext_joinbss_event_callback(adapter, pnetwork->join_res);
+
+	rtw_mi_os_xmit_schedule(adapter);
+
+}
+
+void rtw_sta_media_status_rpt(_adapter *adapter, struct sta_info *sta, bool connected)
+{
+	struct macid_ctl_t *macid_ctl = &adapter->dvobj->macid_ctl;
+	bool miracast_enabled = 0;
+	bool miracast_sink = 0;
+	u8 role = H2C_MSR_ROLE_RSVD;
+
+	if (sta == NULL) {
+		RTW_PRINT(FUNC_ADPT_FMT" sta is NULL\n"
+			  , FUNC_ADPT_ARG(adapter));
+		rtw_warn_on(1);
+		return;
+	}
+
+	if (sta->mac_id >= macid_ctl->num) {
+		RTW_PRINT(FUNC_ADPT_FMT" invalid macid:%u\n"
+			  , FUNC_ADPT_ARG(adapter), sta->mac_id);
+		rtw_warn_on(1);
+		return;
+	}
+
+	if (!rtw_macid_is_used(macid_ctl, sta->mac_id)) {
+		RTW_PRINT(FUNC_ADPT_FMT" macid:%u not is used, set connected to 0\n"
+			  , FUNC_ADPT_ARG(adapter), sta->mac_id);
+		connected = 0;
+		rtw_warn_on(1);
+	}
+
+	if (connected && !rtw_macid_is_bmc(macid_ctl, sta->mac_id)) {
+		miracast_enabled = STA_OP_WFD_MODE(sta) != 0 && is_miracast_enabled(adapter);
+		miracast_sink = miracast_enabled && (STA_OP_WFD_MODE(sta) & MIRACAST_SINK);
+
+			if (MLME_IS_STA(adapter)) {
+				if (MLME_IS_GC(adapter))
+					role = H2C_MSR_ROLE_GO;
+				else
+					role = H2C_MSR_ROLE_AP;
+			} else if (MLME_IS_AP(adapter)) {
+				if (MLME_IS_GO(adapter))
+					role = H2C_MSR_ROLE_GC;
+				else
+					role = H2C_MSR_ROLE_STA;
+			} else if (MLME_IS_ADHOC(adapter) || MLME_IS_ADHOC_MASTER(adapter))
+				role = H2C_MSR_ROLE_ADHOC;
+
+		if (role == H2C_MSR_ROLE_GC
+		    || role == H2C_MSR_ROLE_GO
+		    || role == H2C_MSR_ROLE_TDLS
+		   ) {
+			if (adapter->wfd_info.rtsp_ctrlport
+			    || adapter->wfd_info.tdls_rtsp_ctrlport
+			    || adapter->wfd_info.peer_rtsp_ctrlport)
+				rtw_wfd_st_switch(sta, 1);
+		}
+	}
+
+	rtw_hal_set_FwMediaStatusRpt_single_cmd(adapter
+						, connected
+						, miracast_enabled
+						, miracast_sink
+						, role
+						, sta->mac_id
+					       );
+}
+
+u8 rtw_sta_media_status_rpt_cmd(_adapter *adapter, struct sta_info *sta, bool connected)
+{
+	struct cmd_priv	*cmdpriv = &adapter->cmdpriv;
+	struct cmd_obj *cmdobj;
+	struct drvextra_cmd_parm *cmd_parm;
+	struct sta_media_status_rpt_cmd_parm *rpt_parm;
+	u8	res = _SUCCESS;
+
+	cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (cmdobj == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (cmd_parm == NULL) {
+		rtw_mfree((u8 *)cmdobj, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	rpt_parm = (struct sta_media_status_rpt_cmd_parm *)rtw_zmalloc(sizeof(struct sta_media_status_rpt_cmd_parm));
+	if (rpt_parm == NULL) {
+		rtw_mfree((u8 *)cmdobj, sizeof(struct cmd_obj));
+		rtw_mfree((u8 *)cmd_parm, sizeof(struct drvextra_cmd_parm));
+		res = _FAIL;
+		goto exit;
+	}
+
+	rpt_parm->sta = sta;
+	rpt_parm->connected = connected;
+
+	cmd_parm->ec_id = STA_MSTATUS_RPT_WK_CID;
+	cmd_parm->type = 0;
+	cmd_parm->size = sizeof(struct sta_media_status_rpt_cmd_parm);
+	cmd_parm->pbuf = (u8 *)rpt_parm;
+	init_h2fwcmd_w_parm_no_rsp(cmdobj, cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(cmdpriv, cmdobj);
+
+exit:
+	return res;
+}
+
+inline void rtw_sta_media_status_rpt_cmd_hdl(_adapter *adapter, struct sta_media_status_rpt_cmd_parm *parm)
+{
+	rtw_sta_media_status_rpt(adapter, parm->sta, parm->connected);
+}
+
+void rtw_stassoc_event_callback(_adapter *adapter, u8 *pbuf)
+{
+	_irqL irqL;
+	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 (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+		psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr);
+		if (psta) {
+			u8 *passoc_req = NULL;
+			u32 assoc_req_len = 0;
+
+			rtw_sta_media_status_rpt(adapter, psta, 1);
+
+
+			ap_sta_info_defer_update(adapter, psta);
+
+			/* report to upper layer */
+			RTW_INFO("indicate_sta_assoc_event to upper layer - hostapd\n");
+			rtw_indicate_sta_assoc_event(adapter, psta);
+
+			if (is_wep_enc(adapter->securitypriv.dot11PrivacyAlgrthm))
+				rtw_ap_wep_pk_setting(adapter, psta);
+		}
+		goto exit;
+	}
+
+	/* for AD-HOC mode */
+	psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr);
+	if (psta == NULL) {
+		RTW_ERR(FUNC_ADPT_FMT" get no sta_info with "MAC_FMT"\n"
+			, FUNC_ADPT_ARG(adapter), MAC_ARG(pstassoc->macaddr));
+		rtw_warn_on(1);
+		goto exit;
+	}
+
+	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;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) ||
+	    (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE)) {
+		if (adapter->stapriv.asoc_sta_count == 2) {
+			_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+			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;
+			_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+			/* a sta + bc/mc_stainfo (not Ibss_stainfo) */
+			rtw_indicate_connect(adapter);
+		}
+	}
+
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+	mlmeext_sta_add_event_callback(adapter, psta);
+
+exit:
+	return;
+}
+
+
+
+void rtw_sta_mstatus_disc_rpt(_adapter *adapter, u8 mac_id)
+{
+	struct macid_ctl_t *macid_ctl = &adapter->dvobj->macid_ctl;
+
+	RTW_INFO("%s "ADPT_FMT" - mac_id=%d\n", __func__, ADPT_ARG(adapter), mac_id);
+
+	if (mac_id >= 0 && mac_id < macid_ctl->num) {
+		rtw_hal_set_FwMediaStatusRpt_single_cmd(adapter, 0, 0, 0, 0, mac_id);
+		/*
+		 * For safety, prevent from keeping macid sleep.
+		 * If we can sure all power mode enter/leave are paired,
+		 * this check can be removed.
+		 * Lucas at 20131113
+		 */
+		/* wakeup macid after disconnect. */
+		/*if (MLME_IS_STA(adapter))*/
+		rtw_hal_macid_wakeup(adapter, mac_id);
+	} else {
+		RTW_PRINT(FUNC_ADPT_FMT" invalid macid:%u\n"
+			  , FUNC_ADPT_ARG(adapter), mac_id);
+		rtw_warn_on(1);
+	}
+}
+void rtw_sta_mstatus_report(_adapter *adapter)
+{
+	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	struct wlan_network *tgt_network = &pmlmepriv->cur_network;
+	struct sta_info *psta = NULL;
+
+	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, WIFI_ASOC_STATE)) {
+		psta = rtw_get_stainfo(&adapter->stapriv, tgt_network->network.MacAddress);
+		if (psta)
+			rtw_sta_mstatus_disc_rpt(adapter, psta->mac_id);
+		else {
+			RTW_INFO("%s "ADPT_FMT" - mac_addr: "MAC_FMT" psta == NULL\n", __func__, ADPT_ARG(adapter), MAC_ARG(tgt_network->network.MacAddress));
+			rtw_warn_on(1);
+		}
+	}
+}
+
+void rtw_stadel_event_callback(_adapter *adapter, u8 *pbuf)
+{
+	_irqL irqL, irqL2;
+
+	struct sta_info *psta;
+	struct wlan_network *pwlan = NULL;
+	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);
+	struct mlme_ext_priv	*pmlmeext = &adapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	RTW_INFO("%s(mac_id=%d)=" MAC_FMT "\n", __func__, pstadel->mac_id, MAC_ARG(pstadel->macaddr));
+	rtw_sta_mstatus_disc_rpt(adapter, pstadel->mac_id);
+
+	psta = rtw_get_stainfo(&adapter->stapriv, pstadel->macaddr);
+
+	if (psta == NULL) {
+		RTW_INFO("%s(mac_id=%d)=" MAC_FMT " psta == NULL\n", __func__, pstadel->mac_id, MAC_ARG(pstadel->macaddr));
+		/*rtw_warn_on(1);*/
+	}
+
+	if (psta)
+		rtw_wfd_st_switch(psta, 0);
+
+	/* if(check_fwstate(pmlmepriv, WIFI_AP_STATE)) */
+	if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) {
+
+		return;
+	}
+
+	mlmeext_sta_del_event_callback(adapter);
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL2);
+
+	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+		u16 reason = *((unsigned short *)(pstadel->rsvd));
+		bool roam = _FALSE;
+		struct wlan_network *roam_target = NULL;
+
+		if (adapter->registrypriv.wifi_spec == 1)
+			roam = _FALSE;
+		else if (reason == WLAN_REASON_EXPIRATION_CHK && rtw_chk_roam_flags(adapter, RTW_ROAM_ON_EXPIRED))
+			roam = _TRUE;
+		else if (reason == WLAN_REASON_ACTIVE_ROAM && rtw_chk_roam_flags(adapter, RTW_ROAM_ACTIVE)) {
+			roam = _TRUE;
+			roam_target = pmlmepriv->roam_network;
+		}
+
+		if (roam == _TRUE) {
+			if (rtw_to_roam(adapter) > 0)
+				rtw_dec_to_roam(adapter); /* this stadel_event is caused by roaming, decrease to_roam */
+			else if (rtw_to_roam(adapter) == 0)
+				rtw_set_to_roam(adapter, adapter->registrypriv.max_roaming_times);
+		} else
+			rtw_set_to_roam(adapter, 0);
+
+		rtw_free_uc_swdec_pending_queue(adapter);
+
+		rtw_free_assoc_resources(adapter, 1);
+		rtw_free_mlme_priv_ie_data(pmlmepriv);
+
+		_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+		/* remove the network entry in scanned_queue */
+		pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress);
+		if ((pwlan)  && (!check_fwstate(pmlmepriv, WIFI_UNDER_WPS))) {
+			pwlan->fixed = _FALSE;
+			rtw_free_network_nolock(adapter, pwlan);
+		}
+		_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+		rtw_indicate_disconnect(adapter, *(u16 *)pstadel->rsvd, pstadel->locally_generated);
+
+		_rtw_roaming(adapter, roam_target);
+	}
+
+	if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ||
+	    check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
+
+		/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
+		rtw_free_stainfo(adapter,  psta);
+		/* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
+
+		if (adapter->stapriv.asoc_sta_count == 1) { /* a sta + bc/mc_stainfo (not Ibss_stainfo) */
+			/* rtw_indicate_disconnect(adapter); */ /* removed at 20091105 */
+			_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+			/* free old ibss network */
+			/* pwlan = rtw_find_network(&pmlmepriv->scanned_queue, pstadel->macaddr); */
+			pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress);
+			if (pwlan) {
+				pwlan->fixed = _FALSE;
+				rtw_free_network_nolock(adapter, pwlan);
+			}
+			_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+			/* re-create ibss */
+			pdev_network = &(adapter->registrypriv.dev_network);
+			pibss = adapter->registrypriv.dev_network.MacAddress;
+
+			_rtw_memcpy(pdev_network, &tgt_network->network, get_WLAN_BSSID_EX_sz(&tgt_network->network));
+
+			_rtw_memset(&pdev_network->Ssid, 0, sizeof(NDIS_802_11_SSID));
+			_rtw_memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(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_create_ibss_cmd(adapter, 0) != _SUCCESS)
+				RTW_ERR("rtw_create_ibss_cmd FAIL\n");
+
+		}
+
+	}
+
+	_exit_critical_bh(&pmlmepriv->lock, &irqL2);
+
+}
+
+void rtw_cpwm_event_callback(PADAPTER padapter, u8 *pbuf)
+{
+
+
+}
+
+void rtw_wmm_event_callback(PADAPTER padapter, u8 *pbuf)
+{
+
+	WMMOnAssocRsp(padapter);
+
+}
+
+/*
+* rtw_join_timeout_handler - Timeout/failure handler for CMD JoinBss
+*/
+void rtw_join_timeout_handler(void *ctx)
+{
+	_adapter *adapter = (_adapter *)ctx;
+	_irqL irqL;
+	struct	mlme_priv *pmlmepriv = &adapter->mlmepriv;
+
+	RTW_INFO("%s, fw_state=%x\n", __FUNCTION__, get_fwstate(pmlmepriv));
+
+	if (RTW_CANNOT_RUN(adapter))
+		return;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	if (rtw_to_roam(adapter) > 0) { /* join timeout caused by roaming */
+		while (1) {
+			rtw_dec_to_roam(adapter);
+			if (rtw_to_roam(adapter) != 0) { /* try another */
+				int do_join_r;
+				RTW_INFO("%s try another roaming\n", __FUNCTION__);
+				do_join_r = rtw_do_join(adapter);
+				if (_SUCCESS != do_join_r) {
+					RTW_INFO("%s roaming do_join return %d\n", __FUNCTION__ , do_join_r);
+					continue;
+				}
+				break;
+			} else {
+				RTW_INFO("%s We've try roaming but fail\n", __FUNCTION__);
+				rtw_indicate_disconnect(adapter, 0, _FALSE);
+				break;
+			}
+		}
+
+	} else
+	{
+		rtw_indicate_disconnect(adapter, 0, _FALSE);
+		free_scanqueue(pmlmepriv);/* ??? */
+
+
+	}
+
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+#ifdef CONFIG_DRVEXT_MODULE_WSC
+	drvext_assoc_fail_indicate(&adapter->drvextpriv);
+#endif
+
+}
+
+/*
+* rtw_scan_timeout_handler - Timeout/Faliure handler for CMD SiteSurvey
+* @adapter: pointer to _adapter structure
+*/
+void rtw_scan_timeout_handler(void *ctx)
+{
+	_adapter *adapter = (_adapter *)ctx;
+	_irqL irqL;
+	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	RTW_INFO(FUNC_ADPT_FMT" fw_state=%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv));
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+
+	rtw_indicate_scan_done(adapter, _TRUE);
+
+}
+
+void rtw_mlme_reset_auto_scan_int(_adapter *adapter, u8 *reason)
+{
+	struct mlme_priv *mlme = &adapter->mlmepriv;
+	struct mlme_ext_priv	*pmlmeext = &adapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 u_ch;
+	u32 interval_ms = 0xffffffff; /* 0xffffffff: special value to make min() works well, also means no auto scan */
+
+	*reason = RTW_AUTO_SCAN_REASON_UNSPECIFIED;
+	rtw_mi_get_ch_setting_union(adapter, &u_ch, NULL, NULL);
+
+	if (hal_chk_bw_cap(adapter, BW_CAP_40M)
+	    && is_client_associated_to_ap(adapter) == _TRUE
+	    && u_ch >= 1 && u_ch <= 14
+	    && adapter->registrypriv.wifi_spec
+	    /* TODO: AP Connected is 40MHz capability? */
+	   ) {
+		interval_ms = rtw_min(interval_ms, 60 * 1000);
+		*reason |= RTW_AUTO_SCAN_REASON_2040_BSS;
+	}
+
+	if (interval_ms == 0xffffffff)
+		interval_ms = 0;
+
+	rtw_mlme_set_auto_scan_int(adapter, interval_ms);
+	return;
+}
+
+void rtw_drv_scan_by_self(_adapter *padapter, u8 reason)
+{
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct rtw_ieee80211_channel ch_for_2040_bss[14] = {
+		{1, RTW_IEEE80211_CHAN_PASSIVE_SCAN},
+		{2, RTW_IEEE80211_CHAN_PASSIVE_SCAN},
+		{3, RTW_IEEE80211_CHAN_PASSIVE_SCAN},
+		{4, RTW_IEEE80211_CHAN_PASSIVE_SCAN},
+		{5, RTW_IEEE80211_CHAN_PASSIVE_SCAN},
+		{6, RTW_IEEE80211_CHAN_PASSIVE_SCAN},
+		{7, RTW_IEEE80211_CHAN_PASSIVE_SCAN},
+		{8, RTW_IEEE80211_CHAN_PASSIVE_SCAN},
+		{9, RTW_IEEE80211_CHAN_PASSIVE_SCAN},
+		{10, RTW_IEEE80211_CHAN_PASSIVE_SCAN},
+		{11, RTW_IEEE80211_CHAN_PASSIVE_SCAN},
+		{12, RTW_IEEE80211_CHAN_PASSIVE_SCAN},
+		{13, RTW_IEEE80211_CHAN_PASSIVE_SCAN},
+		{14, RTW_IEEE80211_CHAN_PASSIVE_SCAN},
+	};
+	struct rtw_ieee80211_channel *ch_sel = NULL;
+	int ch_num = 0;
+
+	if (rtw_is_scan_deny(padapter))
+		goto exit;
+
+	if (!rtw_is_adapter_up(padapter))
+		goto exit;
+
+	if (rtw_mi_busy_traffic_check(padapter, _FALSE)) {
+		if (rtw_chk_roam_flags(padapter, RTW_ROAM_ACTIVE) && pmlmepriv->need_to_roam == _TRUE) {
+			RTW_INFO("need to roam, don't care BusyTraffic\n");
+		} else
+		{
+			RTW_INFO(FUNC_ADPT_FMT" exit BusyTraffic\n", FUNC_ADPT_ARG(padapter));
+			goto exit;
+		}
+	}
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) && check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
+		RTW_INFO(FUNC_ADPT_FMT" WIFI_AP_STATE && WIFI_UNDER_WPS\n", FUNC_ADPT_ARG(padapter));
+		goto exit;
+	}
+	if (check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY | _FW_UNDER_LINKING)) == _TRUE) {
+		RTW_INFO(FUNC_ADPT_FMT" _FW_UNDER_SURVEY|_FW_UNDER_LINKING\n", FUNC_ADPT_ARG(padapter));
+		goto exit;
+	}
+
+
+	RTW_INFO(FUNC_ADPT_FMT" reason:0x%02x\n", FUNC_ADPT_ARG(padapter), reason);
+
+	/* only for 20/40 BSS */
+	if (reason == RTW_AUTO_SCAN_REASON_2040_BSS) {
+		ch_sel = ch_for_2040_bss;
+		ch_num = 14;
+	}
+
+	rtw_set_802_11_bssid_list_scan(padapter, NULL, 0, ch_sel, ch_num);
+exit:
+	return;
+}
+
+static void rtw_auto_scan_handler(_adapter *padapter)
+{
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	u8 reason = RTW_AUTO_SCAN_REASON_UNSPECIFIED;
+
+	rtw_mlme_reset_auto_scan_int(padapter, &reason);
+
+	if (!rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE))
+		goto exit;
+
+	if (pmlmepriv->auto_scan_int_ms == 0
+	    || rtw_get_passing_time_ms(pmlmepriv->scan_start_time) < pmlmepriv->auto_scan_int_ms)
+		goto exit;
+
+	rtw_drv_scan_by_self(padapter, reason);
+
+exit:
+	return;
+}
+static u8 is_drv_in_lps(_adapter *adapter)
+{
+	u8 is_in_lps = _FALSE;
+
+	return is_in_lps;
+}
+void rtw_iface_dynamic_check_timer_handlder(_adapter *adapter)
+{
+	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+
+	if (adapter->net_closed == _TRUE)
+		return;
+
+	/* auto site survey */
+	rtw_auto_scan_handler(adapter);
+
+
+	rcu_read_lock();
+
+	if (rcu_dereference(adapter->pnetdev->rx_handler_data)
+		&& (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) == _TRUE)) {
+		/* expire NAT2.5 entry */
+		void nat25_db_expire(_adapter *priv);
+		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 DBG_TRAFFIC_STATISTIC*/
+static void collect_traffic_statistics(_adapter *padapter)
+{
+	struct dvobj_priv	*pdvobjpriv = adapter_to_dvobj(padapter);
+
+	/*_rtw_memset(&pdvobjpriv->traffic_stat, 0, sizeof(struct rtw_traffic_statistics));*/
+
+	/* Tx bytes reset*/
+	pdvobjpriv->traffic_stat.tx_bytes = 0;
+	pdvobjpriv->traffic_stat.tx_pkts = 0;
+	pdvobjpriv->traffic_stat.tx_drop = 0;
+
+	/* Rx bytes reset*/
+	pdvobjpriv->traffic_stat.rx_bytes = 0;
+	pdvobjpriv->traffic_stat.rx_pkts = 0;
+	pdvobjpriv->traffic_stat.rx_drop = 0;
+
+	rtw_mi_traffic_statistics(padapter);
+
+	/* Calculate throughput in last interval */
+	pdvobjpriv->traffic_stat.cur_tx_bytes = pdvobjpriv->traffic_stat.tx_bytes - pdvobjpriv->traffic_stat.last_tx_bytes;
+	pdvobjpriv->traffic_stat.cur_rx_bytes = pdvobjpriv->traffic_stat.rx_bytes - pdvobjpriv->traffic_stat.last_rx_bytes;
+	pdvobjpriv->traffic_stat.last_tx_bytes = pdvobjpriv->traffic_stat.tx_bytes;
+	pdvobjpriv->traffic_stat.last_rx_bytes = pdvobjpriv->traffic_stat.rx_bytes;
+
+	pdvobjpriv->traffic_stat.cur_tx_tp = (u32)(pdvobjpriv->traffic_stat.cur_tx_bytes * 8 / 2 / 1024 / 1024);
+	pdvobjpriv->traffic_stat.cur_rx_tp = (u32)(pdvobjpriv->traffic_stat.cur_rx_bytes * 8 / 2 / 1024 / 1024);
+
+	#ifdef DBG_TRAFFIC_STATISTIC
+	RTW_INFO("\n========================\n");
+	RTW_INFO("cur_tx_bytes:%lld\n", pdvobjpriv->traffic_stat.cur_tx_bytes);
+	RTW_INFO("cur_rx_bytes:%lld\n", pdvobjpriv->traffic_stat.cur_rx_bytes);
+
+	RTW_INFO("last_tx_bytes:%lld\n", pdvobjpriv->traffic_stat.last_tx_bytes);
+	RTW_INFO("last_rx_bytes:%lld\n", pdvobjpriv->traffic_stat.last_rx_bytes);
+
+	RTW_INFO("cur_tx_tp:%d\n", pdvobjpriv->traffic_stat.cur_tx_tp);
+	RTW_INFO("cur_rx_tp:%d\n", pdvobjpriv->traffic_stat.cur_rx_tp);
+	#endif
+}
+
+void rtw_dynamic_check_timer_handlder(void *ctx)
+{
+	struct dvobj_priv *pdvobj = (struct dvobj_priv *)ctx;
+	_adapter *adapter = dvobj_get_primary_adapter(pdvobj);
+
+	if (adapter->registrypriv.mp_mode == 1 && adapter->mppriv.mp_dm == 0) { /* for MP ODM dynamic Tx power tracking */
+		/* RTW_INFO("%s mp_dm =0 return\n", __func__); */
+		goto exit;
+	}
+
+	if (!adapter)
+		goto exit;
+
+	if (!rtw_is_hw_init_completed(adapter))
+		goto exit;
+
+	if (RTW_CANNOT_RUN(adapter))
+		goto exit;
+
+	collect_traffic_statistics(adapter);
+
+	rtw_mi_dynamic_check_timer_handlder(adapter);
+
+	if (!is_drv_in_lps(adapter))
+		rtw_dynamic_chk_wk_cmd(adapter);
+
+exit:
+	_set_timer(&pdvobj->dynamic_chk_timer, 2000);
+}
+
+
+/*
+* Select a new roaming candidate from the original @param candidate and @param competitor
+* @return _TRUE: candidate is updated
+* @return _FALSE: candidate is not updated
+*/
+static int rtw_check_roaming_candidate(struct mlme_priv *mlme
+	, struct wlan_network **candidate, struct wlan_network *competitor)
+{
+	int updated = _FALSE;
+	_adapter *adapter = container_of(mlme, _adapter, mlmepriv);
+
+	if (is_same_ess(&competitor->network, &mlme->cur_network.network) == _FALSE)
+		goto exit;
+
+	if (rtw_is_desired_network(adapter, competitor) == _FALSE)
+		goto exit;
+
+	if (mlme->need_to_roam == _FALSE)
+		goto exit;
+
+
+	RTW_INFO("roam candidate:%s %s("MAC_FMT", ch%3u) rssi:%d, age:%5d\n",
+		 (competitor == mlme->cur_network_scanned) ? "*" : " " ,
+		 competitor->network.Ssid.Ssid,
+		 MAC_ARG(competitor->network.MacAddress),
+		 competitor->network.Configuration.DSConfig,
+		 (int)competitor->network.Rssi,
+		 rtw_get_passing_time_ms(competitor->last_scanned)
+		);
+
+	/* got specific addr to roam */
+	if (!is_zero_mac_addr(mlme->roam_tgt_addr)) {
+		if (_rtw_memcmp(mlme->roam_tgt_addr, competitor->network.MacAddress, ETH_ALEN) == _TRUE)
+			goto update;
+		else
+			goto exit;
+	}
+	if (rtw_get_passing_time_ms((u32)competitor->last_scanned) >= mlme->roam_scanr_exp_ms)
+		goto exit;
+
+	if (competitor->network.Rssi - mlme->cur_network_scanned->network.Rssi < mlme->roam_rssi_diff_th)
+		goto exit;
+
+	if (*candidate != NULL && (*candidate)->network.Rssi >= competitor->network.Rssi)
+		goto exit;
+
+update:
+	*candidate = competitor;
+	updated = _TRUE;
+
+exit:
+	return updated;
+}
+
+int rtw_select_roaming_candidate(struct mlme_priv *mlme)
+{
+	_irqL	irqL;
+	int ret = _FAIL;
+	_list	*phead;
+	_adapter *adapter;
+	_queue	*queue	= &(mlme->scanned_queue);
+	struct	wlan_network	*pnetwork = NULL;
+	struct	wlan_network	*candidate = NULL;
+	u8		bSupportAntDiv = _FALSE;
+
+	if (mlme->cur_network_scanned == NULL) {
+		rtw_warn_on(1);
+		goto exit;
+	}
+
+	_enter_critical_bh(&(mlme->scanned_queue.lock), &irqL);
+	phead = get_list_head(queue);
+	adapter = (_adapter *)mlme->nic_hdl;
+
+	mlme->pscanned = get_next(phead);
+
+	while (!rtw_end_of_queue_search(phead, mlme->pscanned)) {
+
+		pnetwork = LIST_CONTAINOR(mlme->pscanned, struct wlan_network, list);
+		if (pnetwork == NULL) {
+			ret = _FAIL;
+			goto exit;
+		}
+
+		mlme->pscanned = get_next(mlme->pscanned);
+
+		if (0)
+			RTW_INFO("%s("MAC_FMT", ch%u) rssi:%d\n"
+				 , pnetwork->network.Ssid.Ssid
+				 , MAC_ARG(pnetwork->network.MacAddress)
+				 , pnetwork->network.Configuration.DSConfig
+				 , (int)pnetwork->network.Rssi);
+
+		rtw_check_roaming_candidate(mlme, &candidate, pnetwork);
+
+	}
+
+	if (candidate == NULL) {
+		RTW_INFO("%s: return _FAIL(candidate == NULL)\n", __FUNCTION__);
+		ret = _FAIL;
+		goto exit;
+	} else {
+		RTW_INFO("%s: candidate: %s("MAC_FMT", ch:%u)\n", __FUNCTION__,
+			candidate->network.Ssid.Ssid, MAC_ARG(candidate->network.MacAddress),
+			 candidate->network.Configuration.DSConfig);
+
+		mlme->roam_network = candidate;
+
+		if (_rtw_memcmp(candidate->network.MacAddress, mlme->roam_tgt_addr, ETH_ALEN) == _TRUE)
+			_rtw_memset(mlme->roam_tgt_addr, 0, ETH_ALEN);
+	}
+
+	ret = _SUCCESS;
+exit:
+	_exit_critical_bh(&(mlme->scanned_queue.lock), &irqL);
+
+	return ret;
+}
+
+/*
+* 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 *mlme
+	    , struct wlan_network **candidate, struct wlan_network *competitor)
+{
+	int updated = _FALSE;
+	_adapter *adapter = container_of(mlme, _adapter, mlmepriv);
+
+	/* check bssid, if needed */
+	if (mlme->assoc_by_bssid == _TRUE) {
+		if (_rtw_memcmp(competitor->network.MacAddress, mlme->assoc_bssid, ETH_ALEN) == _FALSE)
+			goto exit;
+	}
+
+	/* check ssid, if needed */
+	if (mlme->assoc_ssid.Ssid[0] && mlme->assoc_ssid.SsidLength) {
+		if (competitor->network.Ssid.SsidLength != mlme->assoc_ssid.SsidLength
+		    || _rtw_memcmp(competitor->network.Ssid.Ssid, mlme->assoc_ssid.Ssid, mlme->assoc_ssid.SsidLength) == _FALSE
+		   )
+			goto exit;
+	}
+
+	if (rtw_is_desired_network(adapter, competitor)  == _FALSE)
+		goto exit;
+
+	if (rtw_to_roam(adapter) > 0) {
+		if (rtw_get_passing_time_ms((u32)competitor->last_scanned) >= mlme->roam_scanr_exp_ms
+		    || is_same_ess(&competitor->network, &mlme->cur_network.network) == _FALSE
+		   )
+			goto exit;
+	}
+
+	if (*candidate == NULL || (*candidate)->network.Rssi < competitor->network.Rssi) {
+		*candidate = competitor;
+		updated = _TRUE;
+	}
+
+	if (updated) {
+		RTW_INFO("[by_bssid:%u][assoc_ssid:%s][to_roam:%u] "
+			 "new candidate: %s("MAC_FMT", ch%u) rssi:%d\n",
+			 mlme->assoc_by_bssid,
+			 mlme->assoc_ssid.Ssid,
+			 rtw_to_roam(adapter),
+			 (*candidate)->network.Ssid.Ssid,
+			 MAC_ARG((*candidate)->network.MacAddress),
+			 (*candidate)->network.Configuration.DSConfig,
+			 (int)(*candidate)->network.Rssi
+			);
+	}
+
+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)
+{
+	_irqL	irqL;
+	int ret;
+	_list	*phead;
+	_adapter *adapter;
+	_queue	*queue	= &(pmlmepriv->scanned_queue);
+	struct	wlan_network	*pnetwork = NULL;
+	struct	wlan_network	*candidate = NULL;
+	u8		bSupportAntDiv = _FALSE;
+
+	adapter = (_adapter *)pmlmepriv->nic_hdl;
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	if (pmlmepriv->roam_network) {
+		candidate = pmlmepriv->roam_network;
+		pmlmepriv->roam_network = NULL;
+		goto candidate_exist;
+	}
+
+	phead = get_list_head(queue);
+	pmlmepriv->pscanned = get_next(phead);
+
+	while (!rtw_end_of_queue_search(phead, pmlmepriv->pscanned)) {
+
+		pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list);
+		if (pnetwork == NULL) {
+			ret = _FAIL;
+			goto exit;
+		}
+
+		pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);
+
+		if (0)
+			RTW_INFO("%s("MAC_FMT", ch%u) rssi:%d\n"
+				 , pnetwork->network.Ssid.Ssid
+				 , MAC_ARG(pnetwork->network.MacAddress)
+				 , pnetwork->network.Configuration.DSConfig
+				 , (int)pnetwork->network.Rssi);
+
+		rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork);
+
+	}
+
+	if (candidate == NULL) {
+		RTW_INFO("%s: return _FAIL(candidate == NULL)\n", __FUNCTION__);
+		ret = _FAIL;
+		goto exit;
+	} else {
+		RTW_INFO("%s: candidate: %s("MAC_FMT", ch:%u)\n", __FUNCTION__,
+			candidate->network.Ssid.Ssid, MAC_ARG(candidate->network.MacAddress),
+			 candidate->network.Configuration.DSConfig);
+		goto candidate_exist;
+	}
+
+candidate_exist:
+
+	/* check for situation of  _FW_LINKED */
+	if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) {
+		RTW_INFO("%s: _FW_LINKED while ask_for_joinbss!!!\n", __FUNCTION__);
+		{
+			rtw_disassoc_cmd(adapter, 0, 0);
+			rtw_indicate_disconnect(adapter, 0, _FALSE);
+			rtw_free_assoc_resources(adapter, 0);
+		}
+	}
+
+	set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
+	ret = rtw_joinbss_cmd(adapter, candidate);
+
+exit:
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	return ret;
+}
+
+sint rtw_set_auth(_adapter *adapter, struct security_priv *psecuritypriv)
+{
+	struct	cmd_obj *pcmd;
+	struct	setauth_parm *psetauthparm;
+	struct	cmd_priv	*pcmdpriv = &(adapter->cmdpriv);
+	sint		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) {
+		rtw_mfree((unsigned char *)pcmd, sizeof(struct	cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	_rtw_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;
+
+	_rtw_init_listhead(&pcmd->list);
+
+	res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+
+exit:
+
+	return res;
+
+}
+
+sint rtw_set_key(_adapter *adapter, struct security_priv *psecuritypriv, sint keyid, u8 set_tx, bool enqueue)
+{
+	u8	keylen;
+	struct cmd_obj		*pcmd;
+	struct setkey_parm	*psetkeyparm;
+	struct cmd_priv		*pcmdpriv = &(adapter->cmdpriv);
+	struct mlme_priv		*pmlmepriv = &(adapter->mlmepriv);
+	sint	res = _SUCCESS;
+
+	psetkeyparm = (struct setkey_parm *)rtw_zmalloc(sizeof(struct setkey_parm));
+	if (psetkeyparm == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	_rtw_memset(psetkeyparm, 0, sizeof(struct setkey_parm));
+
+	if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
+		psetkeyparm->algorithm = (unsigned char)psecuritypriv->dot118021XGrpPrivacy;
+	} else {
+		psetkeyparm->algorithm = (u8)psecuritypriv->dot11PrivacyAlgrthm;
+
+	}
+	psetkeyparm->keyid = (u8)keyid;/* 0~3 */
+	psetkeyparm->set_tx = set_tx;
+	if (is_wep_enc(psetkeyparm->algorithm))
+		adapter->securitypriv.key_mask |= BIT(psetkeyparm->keyid);
+
+	RTW_INFO("==> rtw_set_key algorithm(%x),keyid(%x),key_mask(%x)\n", psetkeyparm->algorithm, psetkeyparm->keyid, adapter->securitypriv.key_mask);
+
+	switch (psetkeyparm->algorithm) {
+
+	case _WEP40_:
+		keylen = 5;
+		_rtw_memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen);
+		break;
+	case _WEP104_:
+		keylen = 13;
+		_rtw_memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen);
+		break;
+	case _TKIP_:
+		keylen = 16;
+		_rtw_memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen);
+		psetkeyparm->grpkey = 1;
+		break;
+	case _AES_:
+		keylen = 16;
+		_rtw_memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen);
+		psetkeyparm->grpkey = 1;
+		break;
+	default:
+		res = _FAIL;
+		rtw_mfree((unsigned char *)psetkeyparm, sizeof(struct setkey_parm));
+		goto exit;
+	}
+
+	if (enqueue) {
+		pcmd = (struct	cmd_obj *)rtw_zmalloc(sizeof(struct	cmd_obj));
+		if (pcmd == NULL) {
+			rtw_mfree((unsigned char *)psetkeyparm, sizeof(struct setkey_parm));
+			res = _FAIL; /* try again */
+			goto exit;
+		}
+
+		pcmd->cmdcode = _SetKey_CMD_;
+		pcmd->parmbuf = (u8 *)psetkeyparm;
+		pcmd->cmdsz = (sizeof(struct setkey_parm));
+		pcmd->rsp = NULL;
+		pcmd->rspsz = 0;
+
+		_rtw_init_listhead(&pcmd->list);
+
+		/* _rtw_init_sema(&(pcmd->cmd_sem), 0); */
+
+		res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+	} else {
+		setkey_hdl(adapter, (u8 *)psetkeyparm);
+		rtw_mfree((u8 *) psetkeyparm, sizeof(struct setkey_parm));
+	}
+exit:
+	return res;
+
+}
+
+/* adjust IEs for rtw_joinbss_cmd in WMM */
+int rtw_restruct_wmm_ie(_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(_adapter *Adapter, u8 *bssid)
+{
+	struct security_priv *psecuritypriv = &Adapter->securitypriv;
+	int i = 0;
+
+	do {
+		if ((psecuritypriv->PMKIDList[i].bUsed) &&
+		    (_rtw_memcmp(psecuritypriv->PMKIDList[i].Bssid, bssid, ETH_ALEN) == _TRUE))
+			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(_adapter *adapter, int iEntry, u8 *ie, uint ie_len)
+{
+	struct security_priv *sec = &adapter->securitypriv;
+
+	if (ie[13] > 20) {
+		int i;
+		u16 pmkid_cnt = RTW_GET_LE16(ie + 14 + 20);
+		if (pmkid_cnt == 1 && _rtw_memcmp(ie + 14 + 20 + 2, &sec->PMKIDList[iEntry].PMKID, 16)) {
+			RTW_INFO(FUNC_ADPT_FMT" has carried the same PMKID:"KEY_FMT"\n"
+				, FUNC_ADPT_ARG(adapter), KEY_ARG(&sec->PMKIDList[iEntry].PMKID));
+			goto exit;
+		}
+
+		RTW_INFO(FUNC_ADPT_FMT" remove original PMKID, count:%u\n"
+			 , FUNC_ADPT_ARG(adapter), pmkid_cnt);
+
+		for (i = 0; i < pmkid_cnt; i++)
+			RTW_INFO("    "KEY_FMT"\n", KEY_ARG(ie + 14 + 20 + 2 + i * 16));
+
+		ie_len -= 2 + pmkid_cnt * 16;
+		ie[13] = 20;
+	}
+
+	if (ie[13] <= 20) {
+		/* The RSN IE didn't include the PMK ID, append the PMK information */
+
+		RTW_INFO(FUNC_ADPT_FMT" append PMKID:"KEY_FMT"\n"
+			, FUNC_ADPT_ARG(adapter), KEY_ARG(&sec->PMKIDList[iEntry].PMKID));
+
+		RTW_PUT_LE16(&ie[ie_len], 1);
+		ie_len += 2;
+
+		_rtw_memcpy(&ie[ie_len], &sec->PMKIDList[iEntry].PMKID, 16);
+		ie_len += 16;
+
+		ie[13] += 18;/* PMKID length = 2+16 */
+	}
+
+exit:
+	return ie_len;
+}
+
+static int rtw_remove_pmkid(_adapter *adapter, u8 *ie, uint ie_len)
+{
+	struct security_priv *sec = &adapter->securitypriv;
+	int i;
+	u16 pmkid_cnt = RTW_GET_LE16(ie + 14 + 20);
+
+	if (ie[13] <= 20)
+		goto exit;
+
+	RTW_INFO(FUNC_ADPT_FMT" remove original PMKID, count:%u\n"
+		 , FUNC_ADPT_ARG(adapter), pmkid_cnt);
+
+	for (i = 0; i < pmkid_cnt; i++)
+		RTW_INFO("    "KEY_FMT"\n", KEY_ARG(ie + 14 + 20 + 2 + i * 16));
+
+	ie_len -= 2 + pmkid_cnt * 16;
+	ie[13] = 20;
+
+exit:
+	return ie_len;
+}
+
+sint rtw_restruct_sec_ie(_adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len)
+{
+	u8 authmode = 0x0, securitytype, match;
+	u8 sec_ie[255], uncst_oui[4], bkup_ie[255];
+	u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01};
+	uint	ielength, cnt, remove_cnt;
+	int iEntry;
+
+	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	struct security_priv *psecuritypriv = &adapter->securitypriv;
+	uint	ndisauthmode = psecuritypriv->ndisauthtype;
+	uint ndissecuritytype = psecuritypriv->ndisencryptstatus;
+
+	/* copy fixed ie only */
+	_rtw_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)) {
+		_rtw_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		 */
+		_rtw_memcpy(&out_ie[ielength], &psecuritypriv->supplicant_ie[0], psecuritypriv->supplicant_ie[1] + 2);
+		/* debug for CONFIG_IEEE80211W
+		{
+			int jj;
+			printk("supplicant_ie_length=%d &&&&&&&&&&&&&&&&&&&\n", psecuritypriv->supplicant_ie[1]+2);
+			for(jj=0; jj < psecuritypriv->supplicant_ie[1]+2; jj++)
+				printk(" %02x ", psecuritypriv->supplicant_ie[jj]);
+			printk("\n");
+		}*/
+		ielength += psecuritypriv->supplicant_ie[1] + 2;
+		rtw_report_sec_ie(adapter, authmode, psecuritypriv->supplicant_ie);
+
+	}
+
+	iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid);
+	if (iEntry < 0) {
+		if (authmode == _WPA2_IE_ID_)
+			ielength = rtw_remove_pmkid(adapter, out_ie, ielength);
+	} else {
+		if (authmode == _WPA2_IE_ID_)
+			ielength = rtw_append_pmkid(adapter, iEntry, out_ie, ielength);
+	}
+
+	return ielength;
+}
+
+void rtw_init_registrypriv_dev_network(_adapter *adapter)
+{
+	struct registry_priv *pregistrypriv = &adapter->registrypriv;
+	WLAN_BSSID_EX    *pdev_network = &pregistrypriv->dev_network;
+	u8 *myhwaddr = adapter_mac_addr(adapter);
+
+	_rtw_memcpy(pdev_network->MacAddress, myhwaddr, ETH_ALEN);
+
+	_rtw_memcpy(&pdev_network->Ssid, &pregistrypriv->ssid, sizeof(NDIS_802_11_SSID));
+
+	pdev_network->Configuration.Length = sizeof(NDIS_802_11_CONFIGURATION);
+	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(_adapter *adapter)
+{
+	int sz = 0;
+	struct registry_priv *pregistrypriv = &adapter->registrypriv;
+	WLAN_BSSID_EX    *pdev_network = &pregistrypriv->dev_network;
+	struct	security_priv	*psecuritypriv = &adapter->securitypriv;
+	struct	wlan_network	*cur_network = &adapter->mlmepriv.cur_network;
+	/* struct	xmit_priv	*pxmitpriv = &adapter->xmitpriv; */
+	struct mlme_ext_priv	*pmlmeext = &adapter->mlmeextpriv;
+
+	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);
+
+	if (cur_network->network.InfrastructureMode == Ndis802_11IBSS) {
+		pdev_network->Configuration.ATIMWindow = (0);
+
+		if (pmlmeext->cur_channel != 0)
+			pdev_network->Configuration.DSConfig = pmlmeext->cur_channel;
+		else
+			pdev_network->Configuration.DSConfig = 1;
+	}
+
+	pdev_network->InfrastructureMode = (cur_network->network.InfrastructureMode);
+
+	/* 1. Supported rates */
+	/* 2. IE */
+
+	/* rtw_set_supported_rate(pdev_network->SupportedRates, pregistrypriv->wireless_mode) ; */ /* will be called in rtw_generate_ie */
+	sz = rtw_generate_ie(pregistrypriv);
+
+	pdev_network->IELength = sz;
+
+	pdev_network->Length = get_WLAN_BSSID_EX_sz((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(_adapter *adapter)
+{
+
+}
+
+/* the fucntion is at passive_level */
+void rtw_joinbss_reset(_adapter *padapter)
+{
+	u8	threshold;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	/* todo: if you want to do something io/reg/hw setting before join_bss, please add code here */
+
+	struct ht_priv		*phtpriv = &pmlmepriv->htpriv;
+
+	pmlmepriv->num_FortyMHzIntolerant = 0;
+
+	pmlmepriv->num_sta_no_ht = 0;
+
+	phtpriv->ampdu_enable = _FALSE;/* reset to disabled */
+
+
+}
+
+void	rtw_ht_use_default_setting(_adapter *padapter)
+{
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	struct ht_priv		*phtpriv = &pmlmepriv->htpriv;
+	struct registry_priv	*pregistrypriv = &padapter->registrypriv;
+	BOOLEAN		bHwLDPCSupport = _FALSE, bHwSTBCSupport = _FALSE;
+
+	if (pregistrypriv->wifi_spec)
+		phtpriv->bss_coexist = 1;
+	else
+		phtpriv->bss_coexist = 0;
+
+	phtpriv->sgi_40m = TEST_FLAG(pregistrypriv->short_gi, BIT1) ? _TRUE : _FALSE;
+	phtpriv->sgi_20m = TEST_FLAG(pregistrypriv->short_gi, BIT0) ? _TRUE : _FALSE;
+
+	/* LDPC support */
+	rtw_hal_get_def_var(padapter, HAL_DEF_RX_LDPC, (u8 *)&bHwLDPCSupport);
+	CLEAR_FLAGS(phtpriv->ldpc_cap);
+	if (bHwLDPCSupport) {
+		if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT4))
+			SET_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_RX);
+	}
+	rtw_hal_get_def_var(padapter, HAL_DEF_TX_LDPC, (u8 *)&bHwLDPCSupport);
+	if (bHwLDPCSupport) {
+		if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT5))
+			SET_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_TX);
+	}
+	if (phtpriv->ldpc_cap)
+		RTW_INFO("[HT] HAL Support LDPC = 0x%02X\n", phtpriv->ldpc_cap);
+
+	/* STBC */
+	rtw_hal_get_def_var(padapter, HAL_DEF_TX_STBC, (u8 *)&bHwSTBCSupport);
+	CLEAR_FLAGS(phtpriv->stbc_cap);
+	if (bHwSTBCSupport) {
+		if (TEST_FLAG(pregistrypriv->stbc_cap, BIT5))
+			SET_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX);
+	}
+	rtw_hal_get_def_var(padapter, HAL_DEF_RX_STBC, (u8 *)&bHwSTBCSupport);
+	if (bHwSTBCSupport) {
+		if (TEST_FLAG(pregistrypriv->stbc_cap, BIT4))
+			SET_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_RX);
+	}
+	if (phtpriv->stbc_cap)
+		RTW_INFO("[HT] HAL Support STBC = 0x%02X\n", phtpriv->stbc_cap);
+
+	/* Beamforming setting */
+	CLEAR_FLAGS(phtpriv->beamform_cap);
+}
+void rtw_build_wmm_ie_ht(_adapter *padapter, u8 *out_ie, uint *pout_len)
+{
+	unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00};
+	int out_len;
+	u8 *pframe;
+
+	if (padapter->mlmepriv.qospriv.qos_option == 0) {
+		out_len = *pout_len;
+		pframe = rtw_set_ie(out_ie + out_len, _VENDOR_SPECIFIC_IE_,
+				    _WMM_IE_Length_, WMM_IE, pout_len);
+
+		padapter->mlmepriv.qospriv.qos_option = 1;
+	}
+}
+
+/* the fucntion is >= passive_level */
+unsigned int rtw_restructure_ht_ie(_adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len, u8 channel)
+{
+	u32 ielen, out_len;
+	u32 rx_packet_offset, max_recvbuf_sz;
+	HT_CAP_AMPDU_FACTOR max_rx_ampdu_factor;
+	HT_CAP_AMPDU_DENSITY best_ampdu_density;
+	unsigned char *p, *pframe;
+	struct rtw_ieee80211_ht_cap ht_capie;
+	u8	cbw40_enable = 0, rf_type = 0, operation_bw = 0, rf_num = 0, rx_stbc_nss = 0, rx_nss = 0;
+	struct registry_priv *pregistrypriv = &padapter->registrypriv;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct ht_priv		*phtpriv = &pmlmepriv->htpriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter);
+
+	phtpriv->ht_option = _FALSE;
+
+	out_len = *pout_len;
+
+	_rtw_memset(&ht_capie, 0, sizeof(struct rtw_ieee80211_ht_cap));
+
+	ht_capie.cap_info = IEEE80211_HT_CAP_DSSSCCK40;
+
+	if (phtpriv->sgi_20m)
+		ht_capie.cap_info |= IEEE80211_HT_CAP_SGI_20;
+
+	/* Get HT BW */
+	if (in_ie == NULL) {
+		/* TDLS: TODO 20/40 issue */
+		if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+			operation_bw = padapter->mlmeextpriv.cur_bwmode;
+			if (operation_bw > CHANNEL_WIDTH_40)
+				operation_bw = CHANNEL_WIDTH_40;
+		} else
+			/* TDLS: TODO 40? */
+			operation_bw = CHANNEL_WIDTH_40;
+	} else {
+		p = rtw_get_ie(in_ie, _HT_ADD_INFO_IE_, &ielen, in_len);
+		if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) {
+			struct HT_info_element *pht_info = (struct HT_info_element *)(p + 2);
+			if (pht_info->infos[0] & BIT(2)) {
+				switch (pht_info->infos[0] & 0x3) {
+				case 1:
+				case 3:
+					operation_bw = CHANNEL_WIDTH_40;
+					break;
+				default:
+					operation_bw = CHANNEL_WIDTH_20;
+					break;
+				}
+			} else
+				operation_bw = CHANNEL_WIDTH_20;
+		}
+	}
+
+	/* to disable 40M Hz support while gd_bw_40MHz_en = 0 */
+	if (hal_chk_bw_cap(padapter, BW_CAP_40M)) {
+		if (channel > 14) {
+			if (REGSTY_IS_BW_5G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_40))
+				cbw40_enable = 1;
+		} else {
+			if (REGSTY_IS_BW_2G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_40))
+				cbw40_enable = 1;
+		}
+	}
+
+	if ((cbw40_enable == 1) && (operation_bw == CHANNEL_WIDTH_40)) {
+		ht_capie.cap_info |= IEEE80211_HT_CAP_SUP_WIDTH;
+		if (phtpriv->sgi_40m)
+			ht_capie.cap_info |= IEEE80211_HT_CAP_SGI_40;
+	}
+
+	/* todo: disable SM power save mode */
+	ht_capie.cap_info |= IEEE80211_HT_CAP_SM_PS;
+
+	/* RX LDPC */
+	if (TEST_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_RX)) {
+		ht_capie.cap_info |= IEEE80211_HT_CAP_LDPC_CODING;
+		RTW_INFO("[HT] Declare supporting RX LDPC\n");
+	}
+
+	/* TX STBC */
+	if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX)) {
+		ht_capie.cap_info |= IEEE80211_HT_CAP_TX_STBC;
+		RTW_INFO("[HT] Declare supporting TX STBC\n");
+	}
+
+	/* RX STBC */
+	if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_RX)) {
+		if ((pregistrypriv->rx_stbc == 0x3) ||							/* enable for 2.4/5 GHz */
+		    ((channel <= 14) && (pregistrypriv->rx_stbc == 0x1)) ||		/* enable for 2.4GHz */
+		    ((channel > 14) && (pregistrypriv->rx_stbc == 0x2)) ||		/* enable for 5GHz */
+		    (pregistrypriv->wifi_spec == 1)) {
+			/* HAL_DEF_RX_STBC means STBC RX spatial stream, todo: VHT 4 streams */
+			rtw_hal_get_def_var(padapter, HAL_DEF_RX_STBC, (u8 *)(&rx_stbc_nss));
+			SET_HT_CAP_ELE_RX_STBC(&ht_capie, rx_stbc_nss);
+			RTW_INFO("[HT] Declare supporting RX STBC = %d\n", rx_stbc_nss);
+		}
+	}
+
+	/* fill default supported_mcs_set */
+	_rtw_memcpy(ht_capie.supp_mcs_set, pmlmeext->default_supported_mcs_set, 16);
+
+	/* update default supported_mcs_set */
+	rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+	rx_nss = rtw_min(rf_type_to_rf_rx_cnt(rf_type), hal_spec->rx_nss_num);
+
+	switch (rx_nss) {
+	case 1:
+		set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_1R);
+		break;
+	case 2:
+			set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_2R);
+		break;
+	case 3:
+		set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_3R);
+		break;
+	case 4:
+		set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_4R);
+		break;
+	default:
+		RTW_WARN("rf_type:%d or rx_nss:%u is not expected\n", rf_type, hal_spec->rx_nss_num);
+	}
+
+	{
+		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);
+		if (max_recvbuf_sz - rx_packet_offset >= (8191 - 256)) {
+			RTW_INFO("%s IEEE80211_HT_CAP_MAX_AMSDU is set\n", __FUNCTION__);
+			ht_capie.cap_info = ht_capie.cap_info | IEEE80211_HT_CAP_MAX_AMSDU;
+		}
+	}
+	/*
+	AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k
+	AMPDU_para [4:2]:Min MPDU Start Spacing
+	*/
+
+	if (padapter->driver_rx_ampdu_factor != 0xFF)
+		max_rx_ampdu_factor = (HT_CAP_AMPDU_FACTOR)padapter->driver_rx_ampdu_factor;
+	else
+		rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor);
+
+	/* 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->driver_rx_ampdu_spacing != 0xFF)
+		ht_capie.ampdu_params_info |= ((padapter->driver_rx_ampdu_spacing & 0x07) << 2);
+	else {
+		if (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_) {
+			/*
+			*	Todo : Each chip must to ask DD , this chip best ampdu_density setting
+			*	By yiwei.sun
+			*/
+			rtw_hal_get_def_var(padapter, HW_VAR_BEST_AMPDU_DENSITY, &best_ampdu_density);
+
+			ht_capie.ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY & (best_ampdu_density << 2));
+
+		} else
+			ht_capie.ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY & 0x00);
+	}
+
+	pframe = rtw_set_ie(out_ie + out_len, _HT_CAPABILITY_IE_,
+		sizeof(struct rtw_ieee80211_ht_cap), (unsigned char *)&ht_capie, pout_len);
+
+	phtpriv->ht_option = _TRUE;
+
+	if (in_ie != NULL) {
+		p = rtw_get_ie(in_ie, _HT_ADD_INFO_IE_, &ielen, in_len);
+		if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) {
+			out_len = *pout_len;
+			pframe = rtw_set_ie(out_ie + out_len, _HT_ADD_INFO_IE_, ielen, p + 2 , pout_len);
+		}
+	}
+
+	return phtpriv->ht_option;
+
+}
+
+/* the fucntion is > passive_level (in critical_section) */
+void rtw_update_ht_cap(_adapter *padapter, u8 *pie, uint ie_len, u8 channel)
+{
+	u8 *p, max_ampdu_sz;
+	int len;
+	/* struct sta_info *bmc_sta, *psta; */
+	struct rtw_ieee80211_ht_cap *pht_capie;
+	struct ieee80211_ht_addt_info *pht_addtinfo;
+	/* struct recv_reorder_ctrl *preorder_ctrl; */
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct ht_priv		*phtpriv = &pmlmepriv->htpriv;
+	/* struct recv_priv *precvpriv = &padapter->recvpriv; */
+	struct registry_priv *pregistrypriv = &padapter->registrypriv;
+	/* struct wlan_network *pcur_network = &(pmlmepriv->cur_network);; */
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 cbw40_enable = 0;
+
+	if (!phtpriv->ht_option)
+		return;
+
+	if ((!pmlmeinfo->HT_info_enable) || (!pmlmeinfo->HT_caps_enable))
+		return;
+
+	RTW_INFO("+rtw_update_ht_cap()\n");
+
+	/* maybe needs check if ap supports rx ampdu. */
+	if ((phtpriv->ampdu_enable == _FALSE) && (pregistrypriv->ampdu_enable == 1)) {
+		if (pregistrypriv->wifi_spec == 1) {
+			/* remove this part because testbed AP should disable RX AMPDU */
+			/* phtpriv->ampdu_enable = _FALSE; */
+			phtpriv->ampdu_enable = _TRUE;
+		} else
+			phtpriv->ampdu_enable = _TRUE;
+	} 
+
+	/* check Max Rx A-MPDU Size */
+	len = 0;
+	p = rtw_get_ie(pie + sizeof(NDIS_802_11_FIXED_IEs), _HT_CAPABILITY_IE_, &len, ie_len - sizeof(NDIS_802_11_FIXED_IEs));
+	if (p && len > 0) {
+		pht_capie = (struct rtw_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); */
+
+		/* RTW_INFO("rtw_update_ht_cap(): max_ampdu_sz=%d\n", max_ampdu_sz); */
+		phtpriv->rx_ampdu_maxlen = max_ampdu_sz;
+
+	}
+
+	len = 0;
+	p = rtw_get_ie(pie + sizeof(NDIS_802_11_FIXED_IEs), _HT_ADD_INFO_IE_, &len, ie_len - sizeof(NDIS_802_11_FIXED_IEs));
+	if (p && len > 0) {
+		pht_addtinfo = (struct ieee80211_ht_addt_info *)(p + 2);
+		/* todo: */
+	}
+
+	if (hal_chk_bw_cap(padapter, BW_CAP_40M)) {
+		if (channel > 14) {
+			if (REGSTY_IS_BW_5G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_40))
+				cbw40_enable = 1;
+		} else {
+			if (REGSTY_IS_BW_2G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_40))
+				cbw40_enable = 1;
+		}
+	}
+
+	/* update cur_bwmode & cur_ch_offset */
+	if ((cbw40_enable) &&
+	    (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & BIT(1)) &&
+	    (pmlmeinfo->HT_info.infos[0] & BIT(2))) {
+		struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter);
+		int i;
+		u8	rf_type = RF_1T1R;
+		u8 tx_nss = 0;
+
+		rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+		tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num);
+
+		/* update the MCS set */
+		for (i = 0; i < 16; i++)
+			pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= pmlmeext->default_supported_mcs_set[i];
+
+		/* update the MCS rates */
+		switch (tx_nss) {
+		case 1:
+			set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_1R);
+			break;
+		case 2:
+				set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R);
+			break;
+		case 3:
+			set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_3R);
+			break;
+		case 4:
+			set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_4R);
+			break;
+		default:
+			RTW_WARN("rf_type:%d or tx_nss_num:%u is not expected\n", rf_type, hal_spec->tx_nss_num);
+		}
+
+		/* switch to the 40M Hz mode accoring to the AP */
+		/* pmlmeext->cur_bwmode = CHANNEL_WIDTH_40; */
+		switch ((pmlmeinfo->HT_info.infos[0] & 0x3)) {
+		case EXTCHNL_OFFSET_UPPER:
+			pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+			break;
+
+		case 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 = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2;
+	if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) {
+		RTW_INFO("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __FUNCTION__);
+	}
+
+	/*  */
+	/* Config current HT Protection mode. */
+	/*  */
+	pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3;
+}
+
+void rtw_issue_addbareq_cmd(_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.bTxBusyTraffic == _FALSE)) */
+	if (bmcst || (padapter->mlmepriv.LinkDetectInfo.NumTxOkInPeriod < 100))
+		return;
+
+	priority = pattrib->priority;
+
+	psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra);
+	if (pattrib->psta != psta) {
+		RTW_INFO("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta);
+		return;
+	}
+
+	if (psta == NULL) {
+		RTW_INFO("%s, psta==NUL\n", __func__);
+		return;
+	}
+
+	if (!(psta->state & _FW_LINKED)) {
+		RTW_INFO("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state);
+		return;
+	}
+
+	phtpriv = &psta->htpriv;
+
+	if ((phtpriv->ht_option == _TRUE) && (phtpriv->ampdu_enable == _TRUE)) {
+		issued = (phtpriv->agg_enable_bitmap >> priority) & 0x1;
+		issued |= (phtpriv->candidate_tid_bitmap >> priority) & 0x1;
+
+		if (0 == issued) {
+			RTW_INFO("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_append_exented_cap(_adapter *padapter, u8 *out_ie, uint *pout_len)
+{
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct ht_priv		*phtpriv = &pmlmepriv->htpriv;
+	struct vht_priv	*pvhtpriv = &pmlmepriv->vhtpriv;
+	u8	cap_content[8] = { 0 };
+	u8	*pframe;
+	u8   null_content[8] = {0};
+
+	if (phtpriv->bss_coexist)
+		SET_EXT_CAPABILITY_ELE_BSS_COEXIST(cap_content, 1);
+
+	if (pvhtpriv->vht_option)
+		SET_EXT_CAPABILITY_ELE_OP_MODE_NOTIF(cap_content, 1);
+	/*
+		From 802.11 specification,if a STA does not support any of capabilities defined
+		in the Extended Capabilities element, then the STA is not required to
+		transmit the Extended Capabilities element.
+	*/
+	if (_FALSE == _rtw_memcmp(cap_content, null_content, 8))
+		pframe = rtw_set_ie(out_ie + *pout_len, EID_EXTCapability, 8, cap_content , pout_len);
+}
+
+inline void rtw_set_to_roam(_adapter *adapter, u8 to_roam)
+{
+	if (to_roam == 0)
+		adapter->mlmepriv.to_join = _FALSE;
+	adapter->mlmepriv.to_roam = to_roam;
+}
+
+inline u8 rtw_dec_to_roam(_adapter *adapter)
+{
+	adapter->mlmepriv.to_roam--;
+	return adapter->mlmepriv.to_roam;
+}
+
+inline u8 rtw_to_roam(_adapter *adapter)
+{
+	return adapter->mlmepriv.to_roam;
+}
+
+void rtw_roaming(_adapter *padapter, struct wlan_network *tgt_network)
+{
+	_irqL irqL;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+	_rtw_roaming(padapter, tgt_network);
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+}
+void _rtw_roaming(_adapter *padapter, struct wlan_network *tgt_network)
+{
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct wlan_network *cur_network = &pmlmepriv->cur_network;
+	int do_join_r;
+
+	if (0 < rtw_to_roam(padapter)) {
+		RTW_INFO("roaming from %s("MAC_FMT"), length:%d\n",
+			cur_network->network.Ssid.Ssid, MAC_ARG(cur_network->network.MacAddress),
+			 cur_network->network.Ssid.SsidLength);
+		_rtw_memcpy(&pmlmepriv->assoc_ssid, &cur_network->network.Ssid, sizeof(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 {
+				RTW_INFO("roaming do_join return %d\n", do_join_r);
+				rtw_dec_to_roam(padapter);
+
+				if (rtw_to_roam(padapter) > 0)
+					continue;
+				else {
+					RTW_INFO("%s(%d) -to roaming fail, indicate_disconnect\n", __FUNCTION__, __LINE__);
+					rtw_indicate_disconnect(padapter, 0, _FALSE);
+					break;
+				}
+			}
+		}
+	}
+
+}
+
+bool rtw_adjust_chbw(_adapter *adapter, u8 req_ch, u8 *req_bw, u8 *req_offset)
+{
+	struct registry_priv *regsty = adapter_to_regsty(adapter);
+	u8 allowed_bw;
+
+	if (req_ch <= 14)
+		allowed_bw = REGSTY_BW_2G(regsty);
+	else
+		allowed_bw = REGSTY_BW_5G(regsty);
+
+	allowed_bw = hal_largest_bw(adapter, allowed_bw);
+
+	if (allowed_bw == CHANNEL_WIDTH_80 && *req_bw > CHANNEL_WIDTH_80)
+		*req_bw = CHANNEL_WIDTH_80;
+	else if (allowed_bw == CHANNEL_WIDTH_40 && *req_bw > CHANNEL_WIDTH_40)
+		*req_bw = CHANNEL_WIDTH_40;
+	else if (allowed_bw == CHANNEL_WIDTH_20 && *req_bw > CHANNEL_WIDTH_20) {
+		*req_bw = CHANNEL_WIDTH_20;
+		*req_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	} else
+		return _FALSE;
+
+	return _TRUE;
+}
+
+sint rtw_linked_check(_adapter *padapter)
+{
+	if ((check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE) ||
+	    (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE) == _TRUE)) {
+		if (padapter->stapriv.asoc_sta_count > 2)
+			return _TRUE;
+	} else {
+		/* Station mode */
+		if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == _TRUE)
+			return _TRUE;
+	}
+	return _FALSE;
+}
+u8 rtw_is_adapter_up(_adapter *padapter)
+{
+	if (padapter == NULL)
+		return _FALSE;
+
+	if (RTW_CANNOT_RUN(padapter)) {
+		RTW_INFO(FUNC_ADPT_FMT "-(bSurpriseRemoved == _TRUE) || ( bDriverStopped == _TRUE)\n", FUNC_ADPT_ARG(padapter));
+		return _FALSE;
+	}
+
+	if (!rtw_is_hw_init_completed(padapter)) {
+		/*RTW_INFO(FUNC_ADPT_FMT "-(hw_init_completed == _FALSE)\n", FUNC_ADPT_ARG(padapter));*/
+		return _FALSE;
+	}
+
+	if (padapter->bup == _FALSE) {
+		/*RTW_INFO(FUNC_ADPT_FMT "-(bup == _FALSE)\n", FUNC_ADPT_ARG(padapter));*/
+		return _FALSE;
+	}
+
+	return _TRUE;
+}
+
+bool is_miracast_enabled(_adapter *adapter)
+{
+	bool enabled = 0;
+	struct wifi_display_info *wfdinfo = &adapter->wfd_info;
+
+	enabled = (wfdinfo->stack_wfd_mode & (MIRACAST_SOURCE | MIRACAST_SINK))
+		  || (wfdinfo->op_wfd_mode & (MIRACAST_SOURCE | MIRACAST_SINK));
+
+	return enabled;
+}
+
+bool rtw_chk_miracast_mode(_adapter *adapter, u8 mode)
+{
+	bool ret = 0;
+	struct wifi_display_info *wfdinfo = &adapter->wfd_info;
+
+	ret = (wfdinfo->stack_wfd_mode & mode) || (wfdinfo->op_wfd_mode & mode);
+
+	return ret;
+}
+
+const char *get_miracast_mode_str(int mode)
+{
+	if (mode == MIRACAST_SOURCE)
+		return "SOURCE";
+	else if (mode == MIRACAST_SINK)
+		return "SINK";
+	else if (mode == (MIRACAST_SOURCE | MIRACAST_SINK))
+		return "SOURCE&SINK";
+	else if (mode == MIRACAST_DISABLED)
+		return "DISABLED";
+	else
+		return "INVALID";
+}
+
+static bool wfd_st_match_rule(_adapter *adapter, u8 *local_naddr, u8 *local_port, u8 *remote_naddr, u8 *remote_port)
+{
+	struct wifi_display_info *wfdinfo = &adapter->wfd_info;
+
+	if (ntohs(*((u16 *)local_port)) == wfdinfo->rtsp_ctrlport
+	    || ntohs(*((u16 *)local_port)) == wfdinfo->tdls_rtsp_ctrlport
+	    || ntohs(*((u16 *)remote_port)) == wfdinfo->peer_rtsp_ctrlport)
+		return _TRUE;
+	return _FALSE;
+}
+
+static struct st_register wfd_st_reg = {
+	.s_proto = 0x06,
+	.rule = wfd_st_match_rule,
+};
+
+inline void rtw_wfd_st_switch(struct sta_info *sta, bool on)
+{
+	if (on)
+		rtw_st_ctl_register(&sta->st_ctl, SESSION_TRACKER_REG_ID_WFD, &wfd_st_reg);
+	else
+		rtw_st_ctl_unregister(&sta->st_ctl, SESSION_TRACKER_REG_ID_WFD);
+}
diff --git a/drivers/staging/rtl8821ce/core/rtw_mlme_ext.c b/drivers/staging/rtl8821ce/core/rtw_mlme_ext.c
new file mode 100644
index 000000000000..61c548a450fd
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/rtw_mlme_ext.c
@@ -0,0 +1,11868 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * 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 <drv_types.h>
+#include <hal_data.h>
+
+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},
+	{WIFI_ACTION_NOACK, "OnActionNoAck",	&OnAction},
+};
+
+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",	&OnAction_ft},
+	{RTW_WLAN_CATEGORY_HT,	"ACTION_HT",	&OnAction_ht},
+	{RTW_WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &DoReserved},
+	{RTW_WLAN_CATEGORY_UNPROTECTED_WNM, "ACTION_UNPROTECTED_WNM", &DoReserved},
+	{RTW_WLAN_CATEGORY_SELF_PROTECTED, "ACTION_SELF_PROTECTED", &DoReserved},
+	{RTW_WLAN_CATEGORY_WMM, "ACTION_WMM", &OnAction_wmm},
+	{RTW_WLAN_CATEGORY_VHT, "ACTION_VHT", &OnAction_vht},
+	{RTW_WLAN_CATEGORY_P2P, "ACTION_P2P", &OnAction_p2p},
+};
+
+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[];
+
+static struct ch_list_t RTW_ChannelPlan2G[] = {
+	/* 0, RTW_RD_2G_NULL */		CH_LIST_ENT(0),
+	/* 1, RTW_RD_2G_WORLD */	CH_LIST_ENT(13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
+	/* 2, RTW_RD_2G_ETSI1 */		CH_LIST_ENT(13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
+	/* 3, RTW_RD_2G_FCC1 */		CH_LIST_ENT(11, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
+	/* 4, RTW_RD_2G_MKK1 */		CH_LIST_ENT(14, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14),
+	/* 5, RTW_RD_2G_ETSI2 */		CH_LIST_ENT(4, 10, 11, 12, 13),
+	/* 6, RTW_RD_2G_GLOBAL */	CH_LIST_ENT(14, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14),
+	/* 7, RTW_RD_2G_MKK2 */		CH_LIST_ENT(13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
+	/* 8, RTW_RD_2G_FCC2 */		CH_LIST_ENT(13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
+};
+
+static struct ch_list_t RTW_ChannelPlan5G[] = {
+	/* 0, RTW_RD_5G_NULL */		CH_LIST_ENT(0),
+	/* 1, RTW_RD_5G_ETSI1 */		CH_LIST_ENT(19, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140),
+	/* 2, RTW_RD_5G_ETSI2 */		CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 3, RTW_RD_5G_ETSI3 */		CH_LIST_ENT(22, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 149, 153, 157, 161, 165),
+	/* 4, RTW_RD_5G_FCC1 */		CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 5, RTW_RD_5G_FCC2 */		CH_LIST_ENT(9, 36, 40, 44, 48, 149, 153, 157, 161, 165),
+	/* 6, RTW_RD_5G_FCC3 */		CH_LIST_ENT(13, 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165),
+	/* 7, RTW_RD_5G_FCC4 */		CH_LIST_ENT(12, 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161),
+	/* 8, RTW_RD_5G_FCC5 */		CH_LIST_ENT(5, 149, 153, 157, 161, 165),
+	/* 9, RTW_RD_5G_FCC6 */		CH_LIST_ENT(8, 36, 40, 44, 48, 52, 56, 60, 64),
+	/* 10, RTW_RD_5G_FCC7 */	CH_LIST_ENT(21, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 11, RTW_RD_5G_KCC1 */	CH_LIST_ENT(19, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 149, 153, 157, 161),
+	/* 12, RTW_RD_5G_MKK1 */	CH_LIST_ENT(19, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140),
+	/* 13, RTW_RD_5G_MKK2 */	CH_LIST_ENT(8, 36, 40, 44, 48, 52, 56, 60, 64),
+	/* 14, RTW_RD_5G_MKK3 */	CH_LIST_ENT(11, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140),
+	/* 15, RTW_RD_5G_NCC1 */	CH_LIST_ENT(16, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 16, RTW_RD_5G_NCC2 */	CH_LIST_ENT(8, 56, 60, 64, 149, 153, 157, 161, 165),
+	/* 17, RTW_RD_5G_NCC3 */	CH_LIST_ENT(5, 149, 153, 157, 161, 165),
+	/* 18, RTW_RD_5G_ETSI4 */	CH_LIST_ENT(4, 36, 40, 44, 48),
+	/* 19, RTW_RD_5G_ETSI5 */	CH_LIST_ENT(21, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 20, RTW_RD_5G_FCC8 */	CH_LIST_ENT(4, 149, 153, 157, 161),
+	/* 21, RTW_RD_5G_ETSI6 */	CH_LIST_ENT(8, 36, 40, 44, 48, 52, 56, 60, 64),
+	/* 22, RTW_RD_5G_ETSI7 */	CH_LIST_ENT(13, 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165),
+	/* 23, RTW_RD_5G_ETSI8 */	CH_LIST_ENT(9, 36, 40, 44, 48, 149, 153, 157, 161, 165),
+	/* 24, RTW_RD_5G_ETSI9 */	CH_LIST_ENT(11, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140),
+	/* 25, RTW_RD_5G_ETSI10 */	CH_LIST_ENT(5, 149, 153, 157, 161, 165),
+	/* 26, RTW_RD_5G_ETSI11 */	CH_LIST_ENT(16, 36, 40, 44, 48, 52, 56, 60, 64, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 27, RTW_RD_5G_NCC4 */	CH_LIST_ENT(17, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 28, RTW_RD_5G_ETSI12 */	CH_LIST_ENT(4, 149, 153, 157, 161),
+	/* 29, RTW_RD_5G_FCC9 */	CH_LIST_ENT(21, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 30, RTW_RD_5G_ETSI13 */	CH_LIST_ENT(16, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140),
+	/* 31, RTW_RD_5G_FCC10 */	CH_LIST_ENT(20, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161),
+	/* 32, RTW_RD_5G_MKK4 */	CH_LIST_ENT(4, 36, 40, 44, 48),
+	/* 33, RTW_RD_5G_ETSI14 */	CH_LIST_ENT(11, 36, 40, 44, 48, 52, 56, 60, 64, 132, 136, 140),
+	/* 34, RTW_RD_5G_FCC11 */	CH_LIST_ENT(25, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165),
+	/* 35, RTW_RD_5G_ETSI15 */	CH_LIST_ENT(21, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 149, 153, 157, 161, 165),
+	/* 36, RTW_RD_5G_MKK5 */	CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 37, RTW_RD_5G_ETSI16 */	CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 38, RTW_RD_5G_ETSI17 */	CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 39, RTW_RD_5G_FCC12*/	CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 40, RTW_RD_5G_FCC13 */	CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 41, RTW_RD_5G_FCC14 */	CH_LIST_ENT(21, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165),
+	/* 42, RTW_RD_5G_FCC15 */	CH_LIST_ENT(13, 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165),
+	/* 43, RTW_RD_5G_FCC16 */	CH_LIST_ENT(13, 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165),
+	/* 44, RTW_RD_5G_ETSI18 */	CH_LIST_ENT(9, 36, 40, 44, 48, 149, 153, 157, 161, 165),
+	/* 45, RTW_RD_5G_ETSI19 */	CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165),
+
+	/* === Below are driver defined for legacy channel plan compatible, NO static index assigned ==== */
+	/* RTW_RD_5G_OLD_FCC1 */	CH_LIST_ENT(20, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165),
+	/* RTW_RD_5G_OLD_NCC1 */	CH_LIST_ENT(15, 56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165),
+	/* RTW_RD_5G_OLD_KCC1 */	CH_LIST_ENT(20, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 149, 153, 157, 161, 165),
+};
+
+static RT_CHANNEL_PLAN_MAP	RTW_ChannelPlanMap[] = {
+	/* ===== 0x00 ~ 0x1F, legacy channel plan ===== */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_KCC1,		TXPWR_LMT_FCC),		/* 0x00, RTW_CHPLAN_FCC */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_OLD_FCC1,	TXPWR_LMT_FCC),		/* 0x01, RTW_CHPLAN_IC */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_ETSI1,	TXPWR_LMT_ETSI),	/* 0x02, RTW_CHPLAN_ETSI */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_NULL,		TXPWR_LMT_ETSI),	/* 0x03, RTW_CHPLAN_SPAIN */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_NULL,		TXPWR_LMT_ETSI),	/* 0x04, RTW_CHPLAN_FRANCE */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_NULL,		TXPWR_LMT_MKK),		/* 0x05, RTW_CHPLAN_MKK */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_NULL,		TXPWR_LMT_MKK),		/* 0x06, RTW_CHPLAN_MKK1 */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_FCC6,		TXPWR_LMT_ETSI),	/* 0x07, RTW_CHPLAN_ISRAEL */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_FCC6,		TXPWR_LMT_MKK),		/* 0x08, RTW_CHPLAN_TELEC */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x09, RTW_CHPLAN_GLOBAL_DOAMIN */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x0A, RTW_CHPLAN_WORLD_WIDE_13 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_OLD_NCC1,	TXPWR_LMT_FCC),		/* 0x0B, RTW_CHPLAN_TAIWAN */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_FCC5,		TXPWR_LMT_ETSI),	/* 0x0C, RTW_CHPLAN_CHINA */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC3,		TXPWR_LMT_WW),		/* 0x0D, RTW_CHPLAN_SINGAPORE_INDIA_MEXICO */ /* ETSI:Singapore, India. FCC:Mexico => WW */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_OLD_KCC1,	TXPWR_LMT_ETSI),	/* 0x0E, RTW_CHPLAN_KOREA */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC6,		TXPWR_LMT_ETSI),	/* 0x0F, RTW_CHPLAN_TURKEY */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_ETSI1,	TXPWR_LMT_MKK),		/* 0x10, RTW_CHPLAN_JAPAN */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC2,		TXPWR_LMT_FCC),		/* 0x11, RTW_CHPLAN_FCC_NO_DFS */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_FCC7,		TXPWR_LMT_MKK),		/* 0x12, RTW_CHPLAN_JAPAN_NO_DFS */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC1,		TXPWR_LMT_WW),		/* 0x13, RTW_CHPLAN_WORLD_WIDE_5G */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_NCC2,		TXPWR_LMT_FCC),		/* 0x14, RTW_CHPLAN_TAIWAN_NO_DFS */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC7,		TXPWR_LMT_ETSI),	/* 0x15, RTW_CHPLAN_ETSI_NO_DFS */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_NCC1,		TXPWR_LMT_ETSI),	/* 0x16, RTW_CHPLAN_KOREA_NO_DFS */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_FCC7,		TXPWR_LMT_MKK),		/* 0x17, RTW_CHPLAN_JAPAN_NO_DFS */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_FCC5,		TXPWR_LMT_ETSI),	/* 0x18, RTW_CHPLAN_PAKISTAN_NO_DFS */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC5,		TXPWR_LMT_FCC),		/* 0x19, RTW_CHPLAN_TAIWAN2_NO_DFS */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x1A, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x1B, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x1C, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x1D, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x1E, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_FCC1,		TXPWR_LMT_WW),		/* 0x1F, RTW_CHPLAN_WORLD_WIDE_ONLY_5G */
+
+	/* ===== 0x20 ~ 0x7F, new channel plan ===== */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x20, RTW_CHPLAN_WORLD_NULL */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_NULL,		TXPWR_LMT_ETSI),	/* 0x21, RTW_CHPLAN_ETSI1_NULL */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_NULL,		TXPWR_LMT_FCC),		/* 0x22, RTW_CHPLAN_FCC1_NULL */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_NULL,		TXPWR_LMT_MKK),		/* 0x23, RTW_CHPLAN_MKK1_NULL */
+	CHPLAN_ENT(RTW_RD_2G_ETSI2,		RTW_RD_5G_NULL,		TXPWR_LMT_ETSI),	/* 0x24, RTW_CHPLAN_ETSI2_NULL */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC1,		TXPWR_LMT_FCC),		/* 0x25, RTW_CHPLAN_FCC1_FCC1 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI1,	TXPWR_LMT_ETSI),	/* 0x26, RTW_CHPLAN_WORLD_ETSI1 */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_MKK1,		TXPWR_LMT_MKK),		/* 0x27, RTW_CHPLAN_MKK1_MKK1 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_KCC1,		TXPWR_LMT_ETSI),	/* 0x28, RTW_CHPLAN_WORLD_KCC1 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC2,		TXPWR_LMT_FCC),		/* 0x29, RTW_CHPLAN_WORLD_FCC2 */
+	CHPLAN_ENT(RTW_RD_2G_FCC2,		RTW_RD_5G_NULL,		TXPWR_LMT_FCC),		/* 0x2A, RTW_CHPLAN_FCC2_NULL */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x2B, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x2C, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x2D, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x2E, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x2F, */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC3,		TXPWR_LMT_FCC),		/* 0x30, RTW_CHPLAN_WORLD_FCC3 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC4,		TXPWR_LMT_FCC),		/* 0x31, RTW_CHPLAN_WORLD_FCC4 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC5,		TXPWR_LMT_FCC),		/* 0x32, RTW_CHPLAN_WORLD_FCC5 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC6,		TXPWR_LMT_FCC),		/* 0x33, RTW_CHPLAN_WORLD_FCC6 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC7,		TXPWR_LMT_FCC),		/* 0x34, RTW_CHPLAN_FCC1_FCC7 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI2,	TXPWR_LMT_ETSI),	/* 0x35, RTW_CHPLAN_WORLD_ETSI2 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI3,	TXPWR_LMT_ETSI),	/* 0x36, RTW_CHPLAN_WORLD_ETSI3 */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_MKK2,		TXPWR_LMT_MKK),		/* 0x37, RTW_CHPLAN_MKK1_MKK2 */
+	CHPLAN_ENT(RTW_RD_2G_MKK1,		RTW_RD_5G_MKK3,		TXPWR_LMT_MKK),		/* 0x38, RTW_CHPLAN_MKK1_MKK3 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_NCC1,		TXPWR_LMT_FCC),		/* 0x39, RTW_CHPLAN_FCC1_NCC1 */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x3A, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x3B, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x3C, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x3D, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x3E, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x3F, */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_NCC2,		TXPWR_LMT_FCC),		/* 0x40, RTW_CHPLAN_FCC1_NCC2 */
+	CHPLAN_ENT(RTW_RD_2G_GLOBAL,	RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x41, RTW_CHPLAN_GLOBAL_NULL */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_ETSI4,	TXPWR_LMT_ETSI),	/* 0x42, RTW_CHPLAN_ETSI1_ETSI4 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC2,		TXPWR_LMT_FCC),		/* 0x43, RTW_CHPLAN_FCC1_FCC2 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_NCC3,		TXPWR_LMT_FCC),		/* 0x44, RTW_CHPLAN_FCC1_NCC3 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI5,	TXPWR_LMT_ETSI),	/* 0x45, RTW_CHPLAN_WORLD_ETSI5 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC8,		TXPWR_LMT_FCC),		/* 0x46, RTW_CHPLAN_FCC1_FCC8 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI6,	TXPWR_LMT_ETSI),	/* 0x47, RTW_CHPLAN_WORLD_ETSI6 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI7,	TXPWR_LMT_ETSI),	/* 0x48, RTW_CHPLAN_WORLD_ETSI7 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI8,	TXPWR_LMT_ETSI),	/* 0x49, RTW_CHPLAN_WORLD_ETSI8 */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x4A, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x4B, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x4C, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x4D, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x4E, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x4F, */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI9,	TXPWR_LMT_ETSI),	/* 0x50, RTW_CHPLAN_WORLD_ETSI9 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI10,	TXPWR_LMT_ETSI),	/* 0x51, RTW_CHPLAN_WORLD_ETSI10 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI11,	TXPWR_LMT_ETSI),	/* 0x52, RTW_CHPLAN_WORLD_ETSI11 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_NCC4,		TXPWR_LMT_FCC),		/* 0x53, RTW_CHPLAN_FCC1_NCC4 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI12,	TXPWR_LMT_ETSI),	/* 0x54, RTW_CHPLAN_WORLD_ETSI12 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC9,		TXPWR_LMT_FCC),		/* 0x55, RTW_CHPLAN_FCC1_FCC9 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI13,	TXPWR_LMT_ETSI),	/* 0x56, RTW_CHPLAN_WORLD_ETSI13 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC10,	TXPWR_LMT_FCC),		/* 0x57, RTW_CHPLAN_FCC1_FCC10 */
+	CHPLAN_ENT(RTW_RD_2G_MKK2,		RTW_RD_5G_MKK4,		TXPWR_LMT_MKK),		/* 0x58, RTW_CHPLAN_MKK2_MKK4 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI14,	TXPWR_LMT_ETSI),	/* 0x59, RTW_CHPLAN_WORLD_ETSI14 */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x5A, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x5B, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x5C, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x5D, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x5E, */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_NULL,		TXPWR_LMT_WW),		/* 0x5F, */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC5,		TXPWR_LMT_FCC),		/* 0x60, RTW_CHPLAN_FCC1_FCC5 */
+	CHPLAN_ENT(RTW_RD_2G_FCC2,		RTW_RD_5G_FCC7,		TXPWR_LMT_FCC),		/* 0x61, RTW_CHPLAN_FCC2_FCC7 */
+	CHPLAN_ENT(RTW_RD_2G_FCC2,		RTW_RD_5G_FCC1,		TXPWR_LMT_FCC),		/* 0x62, RTW_CHPLAN_FCC2_FCC1 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_ETSI15,	TXPWR_LMT_ETSI),	/* 0x63, RTW_CHPLAN_WORLD_ETSI15 */
+	CHPLAN_ENT(RTW_RD_2G_MKK2,		RTW_RD_5G_MKK5,		TXPWR_LMT_MKK),		/* 0x64, RTW_CHPLAN_MKK2_MKK5 */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_ETSI16,	TXPWR_LMT_ETSI),	/* 0x65, RTW_CHPLAN_ETSI1_ETSI16 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC14,	TXPWR_LMT_FCC),		/* 0x66, RTW_CHPLAN_FCC1_FCC14 */
+	CHPLAN_ENT(RTW_RD_2G_FCC1,		RTW_RD_5G_FCC12,	TXPWR_LMT_FCC),		/* 0x67, RTW_CHPLAN_FCC1_FCC12 */
+	CHPLAN_ENT(RTW_RD_2G_FCC2,		RTW_RD_5G_FCC14,	TXPWR_LMT_FCC),		/* 0x68, RTW_CHPLAN_FCC2_FCC14 */
+	CHPLAN_ENT(RTW_RD_2G_FCC2,		RTW_RD_5G_FCC12,	TXPWR_LMT_FCC),		/* 0x69, RTW_CHPLAN_FCC2_FCC12 */
+	CHPLAN_ENT(RTW_RD_2G_ETSI1,		RTW_RD_5G_ETSI17,	TXPWR_LMT_ETSI),	/* 0x6A, RTW_CHPLAN_ETSI1_ETSI17 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC16,	TXPWR_LMT_FCC),		/* 0x6B, RTW_CHPLAN_WORLD_FCC16 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC13,	TXPWR_LMT_FCC),		/* 0x6C, RTW_CHPLAN_WORLD_FCC13 */
+	CHPLAN_ENT(RTW_RD_2G_FCC2,		RTW_RD_5G_FCC15,	TXPWR_LMT_FCC),		/* 0x6D, RTW_CHPLAN_FCC2_FCC15 */
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC12,	TXPWR_LMT_FCC),		/* 0x6E, RTW_CHPLAN_WORLD_FCC12 */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_ETSI8,	TXPWR_LMT_ETSI),	/* 0x6F, RTW_CHPLAN_NULL_ETSI8 */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_ETSI18,	TXPWR_LMT_ETSI),	/* 0x70, RTW_CHPLAN_NULL_ETSI18 */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_ETSI17,	TXPWR_LMT_ETSI),	/* 0x71, RTW_CHPLAN_NULL_ETSI17 */
+	CHPLAN_ENT(RTW_RD_2G_NULL,		RTW_RD_5G_ETSI19,	TXPWR_LMT_ETSI),	/* 0x72, RTW_CHPLAN_NULL_ETSI19 */
+};
+
+static RT_CHANNEL_PLAN_MAP RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE =
+	CHPLAN_ENT(RTW_RD_2G_WORLD,		RTW_RD_5G_FCC1,		TXPWR_LMT_FCC);		/* 0x7F, Realtek Define */
+
+bool rtw_chplan_is_empty(u8 id)
+{
+	RT_CHANNEL_PLAN_MAP *chplan_map;
+
+	if (id == RTW_CHPLAN_REALTEK_DEFINE)
+		chplan_map = &RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE;
+	else
+		chplan_map = &RTW_ChannelPlanMap[id];
+
+	if (chplan_map->Index2G == RTW_RD_2G_NULL
+		&& chplan_map->Index5G == RTW_RD_5G_NULL
+	)
+		return _TRUE;
+
+	return _FALSE;
+}
+
+inline u8 rtw_rd_5g_band1_passive(u8 rtw_rd_5g)
+{
+	u8 passive = 0;
+
+	switch (rtw_rd_5g) {
+	case RTW_RD_5G_FCC13:
+	case RTW_RD_5G_FCC16:
+	case RTW_RD_5G_ETSI18:
+	case RTW_RD_5G_ETSI19:
+		passive = 1;
+	};
+
+	return passive;
+}
+
+inline u8 rtw_rd_5g_band4_passive(u8 rtw_rd_5g)
+{
+	u8 passive = 0;
+
+	switch (rtw_rd_5g) {
+	case RTW_RD_5G_MKK5:
+	case RTW_RD_5G_ETSI16:
+	case RTW_RD_5G_ETSI18:
+	case RTW_RD_5G_ETSI19:
+		passive = 1;
+	};
+
+	return passive;
+}
+
+void rtw_rfctl_init(_adapter *adapter)
+{
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+
+	_rtw_memset(rfctl, 0, sizeof(*rfctl));
+
+}
+
+/* choose channel with shortest waiting (non ocp + cac) time */
+bool rtw_choose_shortest_waiting_ch(_adapter *adapter, u8 req_bw, u8 *dec_ch, u8 *dec_bw, u8 *dec_offset, u8 d_flags)
+{
+#ifndef DBG_CHOOSE_SHORTEST_WAITING_CH
+#define DBG_CHOOSE_SHORTEST_WAITING_CH 0
+#endif
+
+	struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+	struct registry_priv *regsty = adapter_to_regsty(adapter);
+	u8 ch, bw, offset;
+	u8 ch_c = 0, bw_c = 0, offset_c = 0;
+	int i;
+	u32 min_waiting_ms = 0;
+
+	if (!dec_ch || !dec_bw || !dec_offset) {
+		rtw_warn_on(1);
+		return _FALSE;
+	}
+
+	/* full search and narrow bw judegement first to avoid potetial judegement timing issue */
+	for (bw = CHANNEL_WIDTH_20; bw <= req_bw; bw++) {
+		if (!hal_is_bw_support(adapter, bw))
+			continue;
+
+		for (i = 0; i < mlmeext->max_chan_nums; i++) {
+			u32 non_ocp_ms = 0;
+			u32 cac_ms = 0;
+			u32 waiting_ms = 0;
+
+			ch = mlmeext->channel_set[i].ChannelNum;
+
+			if ((d_flags & RTW_CHF_2G) && ch <= 14)
+				continue;
+
+			if ((d_flags & RTW_CHF_5G) && ch > 14)
+				continue;
+
+			if (ch > 14) {
+				if (bw > REGSTY_BW_5G(regsty))
+					continue;
+			} else {
+				if (bw > REGSTY_BW_2G(regsty))
+					continue;
+			}
+
+			if (!rtw_get_offset_by_chbw(ch, bw, &offset))
+				continue;
+
+			if (!rtw_chset_is_chbw_valid(mlmeext->channel_set, ch, bw, offset))
+				continue;
+
+			if ((d_flags & RTW_CHF_NON_OCP) && rtw_chset_is_ch_non_ocp(mlmeext->channel_set, ch, bw, offset))
+				continue;
+
+			if ((d_flags & RTW_CHF_DFS) && rtw_is_dfs_chbw(ch, bw, offset))
+				continue;
+
+			if ((d_flags & RTW_CHF_LONG_CAC) && rtw_is_long_cac_ch(ch, bw, offset, rtw_odm_get_dfs_domain(adapter)))
+				continue;
+
+			if ((d_flags & RTW_CHF_NON_DFS) && !rtw_is_dfs_chbw(ch, bw, offset))
+				continue;
+
+			if ((d_flags & RTW_CHF_NON_LONG_CAC) && !rtw_is_long_cac_ch(ch, bw, offset, rtw_odm_get_dfs_domain(adapter)))
+				continue;
+
+
+			if (DBG_CHOOSE_SHORTEST_WAITING_CH)
+				RTW_INFO(FUNC_ADPT_FMT":%u,%u,%u %u(non_ocp:%u, cac:%u)\n"
+					, FUNC_ADPT_ARG(adapter), ch, bw, offset, waiting_ms, non_ocp_ms, cac_ms);
+
+			if (ch_c == 0
+				|| min_waiting_ms > waiting_ms
+				|| (min_waiting_ms == waiting_ms && bw > bw_c) /* wider bw first */
+			) {
+				ch_c = ch;
+				bw_c = bw;
+				offset_c = offset;
+				min_waiting_ms = waiting_ms;
+			}
+		}
+	}
+
+	if (ch_c != 0) {
+		RTW_INFO(FUNC_ADPT_FMT": d_flags:0x%02x %u,%u,%u waiting_ms:%u\n"
+			, FUNC_ADPT_ARG(adapter), d_flags, ch_c, bw_c, offset_c, min_waiting_ms);
+
+		*dec_ch = ch_c;
+		*dec_bw = bw_c;
+		*dec_offset = offset_c;
+		return _TRUE;
+	}
+
+	if (d_flags == 0)
+		rtw_warn_on(1);
+
+	return _FALSE;
+}
+
+void dump_country_chplan(void *sel, const struct country_chplan *ent)
+{
+	_RTW_PRINT_SEL(sel, "\"%c%c\", 0x%02X%s\n"
+		, ent->alpha2[0], ent->alpha2[1], ent->chplan
+		, COUNTRY_CHPLAN_EN_11AC(ent) ? " ac" : ""
+	);
+}
+
+void dump_country_chplan_map(void *sel)
+{
+	const struct country_chplan *ent;
+	u8 code[2];
+
+
+	for (code[0] = 'A'; code[0] <= 'Z'; code[0]++) {
+		for (code[1] = 'A'; code[1] <= 'Z'; code[1]++) {
+			ent = rtw_get_chplan_from_country(code);
+			if (!ent)
+				continue;
+
+			dump_country_chplan(sel, ent);
+		}
+	}
+}
+
+void dump_chplan_id_list(void *sel)
+{
+	int i;
+
+	for (i = 0; i < RTW_CHPLAN_MAX; i++) {
+		if (!rtw_is_channel_plan_valid(i))
+			continue;
+
+		_RTW_PRINT_SEL(sel, "0x%02X ", i);
+	}
+
+	RTW_PRINT_SEL(sel, "0x7F\n");
+}
+
+void dump_chplan_test(void *sel)
+{
+	int i, j;
+
+	/* check invalid channel */
+	for (i = 0; i < RTW_RD_2G_MAX; i++) {
+		for (j = 0; j < CH_LIST_LEN(RTW_ChannelPlan2G[i]); j++) {
+			if (rtw_ch2freq(CH_LIST_CH(RTW_ChannelPlan2G[i], j)) == 0)
+				RTW_PRINT_SEL(sel, "invalid ch:%u at (%d,%d)\n", CH_LIST_CH(RTW_ChannelPlan2G[i], j), i, j);
+		}
+	}
+
+	for (i = 0; i < RTW_RD_5G_MAX; i++) {
+		for (j = 0; j < CH_LIST_LEN(RTW_ChannelPlan5G[i]); j++) {
+			if (rtw_ch2freq(CH_LIST_CH(RTW_ChannelPlan5G[i], j)) == 0)
+				RTW_PRINT_SEL(sel, "invalid ch:%u at (%d,%d)\n", CH_LIST_CH(RTW_ChannelPlan5G[i], j), i, j);
+		}
+	}
+}
+
+void dump_chset(void *sel, RT_CHANNEL_INFO *ch_set)
+{
+	u8	i;
+
+	for (i = 0; i < MAX_CHANNEL_NUM && ch_set[i].ChannelNum != 0; i++) {
+		RTW_PRINT_SEL(sel, "ch:%3u, freq:%u, scan_type:%d"
+			, ch_set[i].ChannelNum, rtw_ch2freq(ch_set[i].ChannelNum), ch_set[i].ScanType);
+
+		_RTW_PRINT_SEL(sel, ", rx_count:%u", ch_set[i].rx_count);
+
+
+		_RTW_PRINT_SEL(sel, "\n");
+	}
+
+	RTW_PRINT_SEL(sel, "total ch number:%d\n", i);
+}
+
+void dump_cur_chset(void *sel, _adapter *adapter)
+{
+	struct mlme_priv *mlme = &adapter->mlmepriv;
+	struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+	struct registry_priv *regsty = adapter_to_regsty(adapter);
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	int i;
+
+	if (mlme->country_ent)
+		dump_country_chplan(sel, mlme->country_ent);
+	else
+		RTW_PRINT_SEL(sel, "chplan:0x%02X\n", mlme->ChannelPlan);
+
+	RTW_PRINT_SEL(sel, "2G_PLS:%u, 5G_PLS:%u\n"
+		, hal_data->Regulation2_4G, hal_data->Regulation5G);
+
+
+	for (i = 0; i < MAX_CHANNEL_NUM; i++)
+		if (regsty->excl_chs[i] != 0)
+			break;
+
+	if (i < MAX_CHANNEL_NUM) {
+		_RTW_PRINT_SEL(sel, "excl_chs:");
+		for (i = 0; i < MAX_CHANNEL_NUM; i++) {
+			if (regsty->excl_chs[i] == 0)
+				break;
+			_RTW_PRINT_SEL(sel, "%u ", regsty->excl_chs[i]);
+		}
+		RTW_PRINT_SEL(sel, "\n");
+	}
+
+	dump_chset(sel, mlmeext->channel_set);
+}
+
+/*
+ * Search the @param ch in given @param ch_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_chset_search_ch(RT_CHANNEL_INFO *ch_set, const u32 ch)
+{
+	int i;
+
+	if (ch == 0)
+		return -1;
+
+	for (i = 0; i < MAX_CHANNEL_NUM && ch_set[i].ChannelNum != 0; i++) {
+		if (ch == ch_set[i].ChannelNum)
+			return i;
+	}
+
+	return -1;
+}
+
+/*
+ * Check if the @param ch, bw, offset is valid for the given @param ch_set
+ * @ch_set: the given channel set
+ * @ch: the given channel number
+ * @bw: the given bandwidth
+ * @offset: the given channel offset
+ *
+ * return valid (1) or not (0)
+ */
+u8 rtw_chset_is_chbw_valid(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset)
+{
+	u8 cch;
+	u8 *op_chs;
+	u8 op_ch_num;
+	u8 valid = 0;
+	int i;
+
+	cch = rtw_get_center_ch(ch, bw, offset);
+
+	if (!rtw_get_op_chs_by_cch_bw(cch, bw, &op_chs, &op_ch_num))
+		goto exit;
+
+	for (i = 0; i < op_ch_num; i++) {
+		if (0)
+			RTW_INFO("%u,%u,%u - cch:%u, bw:%u, op_ch:%u\n", ch, bw, offset, cch, bw, *(op_chs + i));
+		if (rtw_chset_search_ch(ch_set, *(op_chs + i)) == -1)
+			break;
+	}
+
+	if (op_ch_num != 0 && i == op_ch_num)
+		valid = 1;
+
+exit:
+	return valid;
+}
+
+/*
+ * Check the @param ch is fit with setband setting of @param adapter
+ * @adapter: the given adapter
+ * @ch: the given channel number
+ *
+ * return _TRUE when check valid, _FALSE not valid
+ */
+bool rtw_mlme_band_check(_adapter *adapter, const u32 ch)
+{
+	if (adapter->setband == WIFI_FREQUENCY_BAND_AUTO /* 2.4G and 5G */
+		|| (adapter->setband == WIFI_FREQUENCY_BAND_2GHZ && ch < 35) /* 2.4G only */
+		|| (adapter->setband == WIFI_FREQUENCY_BAND_5GHZ && ch > 35) /* 5G only */
+	)
+		return _TRUE;
+	return _FALSE;
+}
+inline void RTW_SET_SCAN_BAND_SKIP(_adapter *padapter, int skip_band)
+{
+	int bs = ATOMIC_READ(&padapter->bandskip);
+
+	bs |= skip_band;
+	ATOMIC_SET(&padapter->bandskip, bs);
+}
+
+inline void RTW_CLR_SCAN_BAND_SKIP(_adapter *padapter, int skip_band)
+{
+	int bs = ATOMIC_READ(&padapter->bandskip);
+
+	bs &= ~(skip_band);
+	ATOMIC_SET(&padapter->bandskip, bs);
+}
+inline int RTW_GET_SCAN_BAND_SKIP(_adapter *padapter)
+{
+	return ATOMIC_READ(&padapter->bandskip);
+}
+
+#define RTW_IS_SCAN_BAND_SKIP(padapter, skip_band) (ATOMIC_READ(&padapter->bandskip) & (skip_band))
+
+bool rtw_mlme_ignore_chan(_adapter *adapter, const u32 ch)
+{
+	if (RTW_IS_SCAN_BAND_SKIP(adapter, BAND_24G) && ch < 35) /* SKIP 2.4G Band channel */
+		return _TRUE;
+	if (RTW_IS_SCAN_BAND_SKIP(adapter, BAND_5G)  && ch > 35) /* SKIP 5G Band channel */
+		return _TRUE;
+
+	return _FALSE;
+}
+
+/****************************************************************************
+
+Following are the initialization functions for WiFi MLME
+
+*****************************************************************************/
+
+int init_hw_mlme_ext(_adapter *padapter)
+{
+	struct	mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+	/* set_opmode_cmd(padapter, infra_client_with_mlme); */ /* removed */
+
+	set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+	return _SUCCESS;
+}
+
+void init_mlme_default_rate_set(_adapter *padapter)
+{
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+	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,};
+	unsigned char	supported_mcs_set[16] = {0xff, 0xff, 0xff, 0x00, 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+
+	_rtw_memcpy(pmlmeext->datarate, mixed_datarate, NumRates);
+	_rtw_memcpy(pmlmeext->basicrate, mixed_basicrate, NumRates);
+
+	_rtw_memcpy(pmlmeext->default_supported_mcs_set, supported_mcs_set, sizeof(pmlmeext->default_supported_mcs_set));
+}
+
+static void init_mlme_ext_priv_value(_adapter *padapter)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	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 = CHANNEL_WIDTH_20;
+	pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+	pmlmeext->retry = 0;
+
+	pmlmeext->cur_wireless_mode = padapter->registrypriv.wireless_mode;
+
+	init_mlme_default_rate_set(padapter);
+
+	if (pmlmeext->cur_channel > 14)
+		pmlmeext->tx_rate = IEEE80211_OFDM_RATE_6MB;
+	else
+		pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB;
+
+	mlmeext_set_scan_state(pmlmeext, SCAN_DISABLE);
+	pmlmeext->sitesurvey_res.channel_idx = 0;
+	pmlmeext->sitesurvey_res.bss_cnt = 0;
+	pmlmeext->sitesurvey_res.scan_ch_ms = SURVEY_TO;
+	pmlmeext->sitesurvey_res.rx_ampdu_accept = RX_AMPDU_ACCEPT_INVALID;
+	pmlmeext->sitesurvey_res.rx_ampdu_size = RX_AMPDU_SIZE_INVALID;
+	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;
+
+	_rtw_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 void init_channel_list(_adapter *padapter, RT_CHANNEL_INFO *channel_set
+	, struct p2p_channels *channel_list)
+{
+	struct registry_priv *regsty = adapter_to_regsty(padapter);
+
+	struct p2p_oper_class_map op_class[] = {
+		{ IEEE80211G,  81,   1,  13,  1, BW20 },
+		{ IEEE80211G,  82,  14,  14,  1, BW20 },
+		{ IEEE80211A, 115,  36,  48,  4, BW20 },
+		{ IEEE80211A, 116,  36,  44,  8, BW40PLUS },
+		{ IEEE80211A, 117,  40,  48,  8, BW40MINUS },
+		{ IEEE80211A, 124, 149, 161,  4, BW20 },
+		{ IEEE80211A, 125, 149, 169,  4, BW20 },
+		{ IEEE80211A, 126, 149, 157,  8, BW40PLUS },
+		{ IEEE80211A, 127, 153, 161,  8, BW40MINUS },
+		{ -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 (rtw_chset_search_ch(channel_set, ch) == -1)
+				continue;
+
+			if ((0 == padapter->registrypriv.ht_enable) && (8 == o->inc))
+				continue;
+
+			if ((REGSTY_IS_BW_5G_SUPPORT(regsty, CHANNEL_WIDTH_40)) &&
+			    ((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;
+
+}
+
+bool rtw_regsty_is_excl_chs(struct registry_priv *regsty, u8 ch)
+{
+	int i;
+
+	for (i = 0; i < MAX_CHANNEL_NUM; i++) {
+		if (regsty->excl_chs[i] == 0)
+			break;
+		if (regsty->excl_chs[i] == ch)
+			return _TRUE;
+	}
+	return _FALSE;
+}
+
+static u8 init_channel_set(_adapter *padapter, u8 ChannelPlan, RT_CHANNEL_INFO *channel_set)
+{
+	struct registry_priv *regsty = adapter_to_regsty(padapter);
+	u8	index, chanset_size = 0;
+	u8	b5GBand = _FALSE, b2_4GBand = _FALSE;
+	u8	Index2G = 0, Index5G = 0;
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(padapter);
+	int i;
+
+	if (!rtw_is_channel_plan_valid(ChannelPlan)) {
+		RTW_ERR("ChannelPlan ID 0x%02X error !!!!!\n", ChannelPlan);
+		return chanset_size;
+	}
+
+	_rtw_memset(channel_set, 0, sizeof(RT_CHANNEL_INFO) * MAX_CHANNEL_NUM);
+
+	if (IsSupported24G(regsty->wireless_mode) && hal_chk_band_cap(padapter, BAND_CAP_2G))
+		b2_4GBand = _TRUE;
+
+	if (is_supported_5g(regsty->wireless_mode) && hal_chk_band_cap(padapter, BAND_CAP_5G))
+		b5GBand = _TRUE;
+
+	if (b2_4GBand == _FALSE && b5GBand == _FALSE) {
+		RTW_WARN("HW band_cap has no intersection with SW wireless_mode setting\n");
+		return chanset_size;
+	}
+
+	if (b2_4GBand) {
+		if (RTW_CHPLAN_REALTEK_DEFINE == ChannelPlan)
+			Index2G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index2G;
+		else
+			Index2G = RTW_ChannelPlanMap[ChannelPlan].Index2G;
+
+		for (index = 0; index < CH_LIST_LEN(RTW_ChannelPlan2G[Index2G]); index++) {
+			if (rtw_regsty_is_excl_chs(regsty, CH_LIST_CH(RTW_ChannelPlan2G[Index2G], index)) == _TRUE)
+				continue;
+
+			if (chanset_size >= MAX_CHANNEL_NUM) {
+				RTW_WARN("chset size can't exceed MAX_CHANNEL_NUM(%u)\n", MAX_CHANNEL_NUM);
+				break;
+			}
+
+			channel_set[chanset_size].ChannelNum = CH_LIST_CH(RTW_ChannelPlan2G[Index2G], index);
+
+			if (RTW_CHPLAN_GLOBAL_DOAMIN == ChannelPlan
+				|| RTW_CHPLAN_GLOBAL_NULL == ChannelPlan
+			) {
+				/* Channel 1~11 is active, and 12~14 is passive */
+				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 (RTW_CHPLAN_WORLD_WIDE_13 == ChannelPlan
+				|| RTW_CHPLAN_WORLD_WIDE_5G == ChannelPlan
+				|| RTW_RD_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++;
+		}
+	}
+
+	if (b5GBand) {
+		if (RTW_CHPLAN_REALTEK_DEFINE == ChannelPlan)
+			Index5G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index5G;
+		else
+			Index5G = RTW_ChannelPlanMap[ChannelPlan].Index5G;
+
+		for (index = 0; index < CH_LIST_LEN(RTW_ChannelPlan5G[Index5G]); index++) {
+			if (rtw_regsty_is_excl_chs(regsty, CH_LIST_CH(RTW_ChannelPlan5G[Index5G], index)) == _TRUE)
+				continue;
+			if (rtw_is_dfs_ch(CH_LIST_CH(RTW_ChannelPlan5G[Index5G], index)))
+				continue;
+
+			if (chanset_size >= MAX_CHANNEL_NUM) {
+				RTW_WARN("chset size can't exceed MAX_CHANNEL_NUM(%u)\n", MAX_CHANNEL_NUM);
+				break;
+			}
+
+			channel_set[chanset_size].ChannelNum = CH_LIST_CH(RTW_ChannelPlan5G[Index5G], index);
+
+			if ((ChannelPlan == RTW_CHPLAN_WORLD_WIDE_5G) /* all channels passive */
+				|| (rtw_is_5g_band1(channel_set[chanset_size].ChannelNum)
+					&& rtw_rd_5g_band1_passive(Index5G)) /* band1 passive */
+				|| (rtw_is_5g_band4(channel_set[chanset_size].ChannelNum)
+					&& rtw_rd_5g_band4_passive(Index5G)) /* band4 passive */
+				|| (rtw_is_dfs_ch(channel_set[chanset_size].ChannelNum)) /* DFS channel(band2, 3) passive */
+			)
+				channel_set[chanset_size].ScanType = SCAN_PASSIVE;
+			else
+				channel_set[chanset_size].ScanType = SCAN_ACTIVE;
+
+			chanset_size++;
+		}
+	}
+
+
+	if (RTW_CHPLAN_REALTEK_DEFINE == ChannelPlan) {
+		hal_data->Regulation2_4G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.regd;
+		hal_data->Regulation5G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.regd;
+	} else {
+		hal_data->Regulation2_4G = RTW_ChannelPlanMap[ChannelPlan].regd;
+		hal_data->Regulation5G = RTW_ChannelPlanMap[ChannelPlan].regd;
+	}
+
+	if (chanset_size)
+		RTW_INFO(FUNC_ADPT_FMT" ChannelPlan ID:0x%02x, ch num:%d\n"
+			, FUNC_ADPT_ARG(padapter), ChannelPlan, chanset_size);
+	else
+		RTW_WARN(FUNC_ADPT_FMT" ChannelPlan ID:0x%02x, final chset has no channel\n"
+			, FUNC_ADPT_ARG(padapter), ChannelPlan);
+
+	return chanset_size;
+}
+
+void init_mlme_ext_timer(_adapter *padapter)
+{
+	struct	mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+	rtw_init_timer(&pmlmeext->survey_timer, padapter, survey_timer_hdl, padapter);
+	rtw_init_timer(&pmlmeext->link_timer, padapter, link_timer_hdl, padapter);
+}
+
+int	init_mlme_ext_priv(_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);
+
+	/* We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */
+	/* _rtw_memset((u8 *)pmlmeext, 0, sizeof(struct mlme_ext_priv)); */
+
+	pmlmeext->padapter = padapter;
+
+	/* fill_fwpriv(padapter, &(pmlmeext->fwpriv)); */
+
+	init_mlme_ext_priv_value(padapter);
+	pmlmeinfo->bAcceptAddbaReq = pregistrypriv->bAcceptAddbaReq;
+
+	init_mlme_ext_timer(padapter);
+
+	init_mlme_ap_info(padapter);
+
+	pmlmeext->max_chan_nums = init_channel_set(padapter, pmlmepriv->ChannelPlan, pmlmeext->channel_set);
+	init_channel_list(padapter, pmlmeext->channel_set, &pmlmeext->channel_list);
+	pmlmeext->last_scan_time = 0;
+	pmlmeext->mlmeext_init = _TRUE;
+
+	pmlmeext->active_keep_alive_check = _TRUE;
+
+
+	return res;
+
+}
+
+void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext)
+{
+	_adapter *padapter = pmlmeext->padapter;
+
+	if (!padapter)
+		return;
+
+	if (rtw_is_drv_stopped(padapter)) {
+		_cancel_timer_ex(&pmlmeext->survey_timer);
+		_cancel_timer_ex(&pmlmeext->link_timer);
+	}
+}
+
+static void _mgt_dispatcher(_adapter *padapter, struct mlme_handler *ptable, union recv_frame *precv_frame)
+{
+	u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+
+	if (ptable->func) {
+		/* receive the frames that ra(a1) is my address or ra(a1) is bc address. */
+		if (!_rtw_memcmp(GetAddr1Ptr(pframe), adapter_mac_addr(padapter), ETH_ALEN) &&
+		    !_rtw_memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN))
+			return;
+
+		ptable->func(padapter, precv_frame);
+	}
+
+}
+
+void mgt_dispatcher(_adapter *padapter, union recv_frame *precv_frame)
+{
+	int index;
+	struct mlme_handler *ptable;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, get_addr2_ptr(pframe));
+	struct dvobj_priv *psdpriv = padapter->dvobj;
+	struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
+
+	if (GetFrameType(pframe) != WIFI_MGT_TYPE) {
+		return;
+	}
+
+	/* receive the frames that ra(a1) is my address or ra(a1) is bc address. */
+	if (!_rtw_memcmp(GetAddr1Ptr(pframe), adapter_mac_addr(padapter), ETH_ALEN) &&
+	    !_rtw_memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN))
+		return;
+
+	ptable = mlme_sta_tbl;
+
+	index = get_frame_sub_type(pframe) >> 4;
+
+	if (index >= (sizeof(mlme_sta_tbl) / sizeof(struct mlme_handler))) {
+		return;
+	}
+	ptable += index;
+
+	if (psta != NULL) {
+		if (GetRetry(pframe)) {
+			if (precv_frame->u.hdr.attrib.seq_num == psta->RxMgmtFrameSeqNum) {
+				/* drop the duplicate management frame */
+				pdbgpriv->dbg_rx_dup_mgt_frame_drop_count++;
+				RTW_INFO("Drop duplicate management frame with seq_num = %d.\n", precv_frame->u.hdr.attrib.seq_num);
+				return;
+			}
+		}
+		psta->RxMgmtFrameSeqNum = precv_frame->u.hdr.attrib.seq_num;
+	}
+
+	switch (get_frame_sub_type(pframe)) {
+	case WIFI_AUTH:
+		if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE)
+			ptable->func = &OnAuth;
+		else
+			ptable->func = &OnAuthClient;
+	/* pass through */
+	case WIFI_ASSOCREQ:
+	case WIFI_REASSOCREQ:
+		_mgt_dispatcher(padapter, ptable, precv_frame);
+		break;
+	case WIFI_PROBEREQ:
+		if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) {
+			_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:
+		/* if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) */
+		_mgt_dispatcher(padapter, ptable, precv_frame);
+		break;
+	default:
+		_mgt_dispatcher(padapter, ptable, precv_frame);
+		if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE)
+			rtw_hostapd_mlme_rx(padapter, precv_frame);
+		break;
+	}
+
+}
+
+u32 p2p_listen_state_process(_adapter *padapter, unsigned char *da)
+{
+	bool response = _TRUE;
+
+		if (padapter->wdinfo.driver_interface == DRIVER_WEXT) {
+			/*	do nothing if the device name is empty */
+			if (!padapter->wdinfo.device_name_len)
+				response	= _FALSE;
+		}
+
+	if (response == _TRUE)
+		issue_probersp_p2p(padapter, da);
+
+	return _SUCCESS;
+}
+
+/****************************************************************************
+
+Following are the callback functions for each subtype of the management frames
+
+*****************************************************************************/
+
+unsigned int OnProbeReq(_adapter *padapter, union 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);
+	WLAN_BSSID_EX	*cur = &(pmlmeinfo->network);
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint len = precv_frame->u.hdr.len;
+	u8 is_valid_p2p_probereq = _FALSE;
+
+
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	struct rx_pkt_attrib	*pattrib = &precv_frame->u.hdr.attrib;
+	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)
+	   ) {
+		/*	Commented by Albert 2011/03/17 */
+		/*	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 (padapter->registrypriv.wifi_spec == 1) {
+			if (pattrib->data_rate <= 3)
+				wifi_test_chk_rate = 0;
+		}
+
+		if (wifi_test_chk_rate == 1) {
+			is_valid_p2p_probereq = process_probe_req_p2p_ie(pwdinfo, pframe, len);
+			if (is_valid_p2p_probereq == _TRUE) {
+				if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) {
+					/* FIXME */
+					if (padapter->wdinfo.driver_interface == DRIVER_WEXT)
+						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:
+
+	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+		return _SUCCESS;
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE &&
+	    check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE | WIFI_AP_STATE) == _FALSE)
+		return _SUCCESS;
+
+	/* RTW_INFO("+OnProbeReq\n"); */
+
+
+
+
+	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 == _TRUE)
+			goto _issue_probersp;
+
+		if ((ielen != 0 && _FALSE == _rtw_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) == _TRUE &&
+		      pmlmepriv->cur_network.join_res == _TRUE)) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
+			/* RTW_INFO("+issue_probersp during ap mode\n"); */
+			issue_probersp(padapter, get_sa(pframe), is_valid_p2p_probereq);
+		}
+
+	}
+
+	return _SUCCESS;
+
+}
+
+unsigned int OnProbeRsp(_adapter *padapter, union recv_frame *precv_frame)
+{
+	struct sta_info		*psta;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct sta_priv		*pstapriv = &padapter->stapriv;
+	u8	*pframe = precv_frame->u.hdr.rx_data;
+	struct wifidirect_info	*pwdinfo = &padapter->wdinfo;
+
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) {
+		if (_TRUE == pwdinfo->tx_prov_disc_info.benable) {
+			if (_rtw_memcmp(pwdinfo->tx_prov_disc_info.peerIFAddr, get_addr2_ptr(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 (_TRUE == pwdinfo->nego_req_info.benable) {
+			RTW_INFO("[%s] P2P State is GONEGO ING!\n", __FUNCTION__);
+			if (_rtw_memcmp(pwdinfo->nego_req_info.peerDevAddr, get_addr2_ptr(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 (_TRUE == pwdinfo->invitereq_info.benable) {
+			RTW_INFO("[%s] P2P_STATE_TX_INVITE_REQ!\n", __FUNCTION__);
+			if (_rtw_memcmp(pwdinfo->invitereq_info.peer_macaddr, get_addr2_ptr(pframe), ETH_ALEN)) {
+				pwdinfo->invitereq_info.benable = _FALSE;
+				issue_p2p_invitation_request(padapter, pwdinfo->invitereq_info.peer_macaddr);
+			}
+		}
+	}
+
+	if (mlmeext_chk_scan_state(pmlmeext, SCAN_PROCESS)) {
+		rtw_mi_report_survey_event(padapter, precv_frame);
+		return _SUCCESS;
+	}
+	
+	return _SUCCESS;
+}
+
+/* for 11n Logo 4.2.31/4.2.32 */
+static void rtw_check_legacy_ap(_adapter *padapter, u8 *pframe, u32 len)
+{
+
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+	if (!padapter->registrypriv.wifi_spec)
+		return;
+	
+	if(!MLME_IS_AP(padapter))
+		return;
+	
+
+	if (pmlmeext->bstart_bss == _TRUE) {
+		int left;
+		u16 capability;
+		unsigned char *pos;
+		struct rtw_ieee802_11_elems elems;
+		struct HT_info_element *pht_info = NULL;
+		u16 cur_op_mode; 
+
+		/* checking IEs */
+		left = len - sizeof(struct rtw_ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_;
+		pos = pframe + sizeof(struct rtw_ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_;
+		if (rtw_ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) {
+			RTW_INFO("%s: parse fail for "MAC_FMT"\n", __func__, MAC_ARG(GetAddr3Ptr(pframe)));
+			return;
+		}
+
+		cur_op_mode = pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+
+		/* for legacy ap */
+		if (elems.ht_capabilities == NULL && elems.ht_capabilities_len == 0) {
+
+			if (0)
+				RTW_INFO("%s: "MAC_FMT" is legacy ap\n", __func__, MAC_ARG(GetAddr3Ptr(pframe)));
+
+			ATOMIC_SET(&pmlmepriv->olbc, _TRUE);
+			ATOMIC_SET(&pmlmepriv->olbc_ht, _TRUE);
+		}
+			
+	}
+}
+
+unsigned int OnBeacon(_adapter *padapter, union recv_frame *precv_frame)
+{
+	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->u.hdr.rx_data;
+	uint len = precv_frame->u.hdr.len;
+	WLAN_BSSID_EX *pbss;
+	int ret = _SUCCESS;
+	u8 *p = NULL;
+	u32 ielen = 0;
+
+	if (validate_beacon_len(pframe, len) == _FALSE)
+		return _SUCCESS;
+	p = rtw_get_ie(pframe + sizeof(struct rtw_ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ielen,
+		precv_frame->u.hdr.len - sizeof(struct rtw_ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_);
+	if ((p != NULL) && (ielen > 0)) {
+		if ((*(p + 1 + ielen) == 0x2D) && (*(p + 2 + ielen) != 0x2D)) {
+			/* Invalid value 0x2D is detected in Extended Supported Rates (ESR) IE. Try to fix the IE length to avoid failed Beacon parsing. */
+			RTW_INFO("[WIFIDBG] Error in ESR IE is detected in Beacon of BSSID:"MAC_FMT". Fix the length of ESR IE to avoid failed Beacon parsing.\n", MAC_ARG(GetAddr3Ptr(pframe)));
+			*(p + 1) = ielen - 1;
+		}
+	}
+
+	if (mlmeext_chk_scan_state(pmlmeext, SCAN_PROCESS)) {
+		rtw_mi_report_survey_event(padapter, precv_frame);
+		return _SUCCESS;
+	}
+
+	rtw_check_legacy_ap(padapter, pframe, len);
+
+	if (_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) {
+		if ((pmlmeinfo->state & WIFI_FW_AUTH_NULL)
+			&& rtw_sta_linking_test_wait_done()
+		) {
+			if (rtw_sta_linking_test_force_fail()) {
+				set_link_timer(pmlmeext, 1);
+				return _SUCCESS;
+			}
+
+			/* we should update current network before auth, or some IE is wrong */
+			pbss = (WLAN_BSSID_EX *)rtw_malloc(sizeof(WLAN_BSSID_EX));
+			if (pbss) {
+				if (collect_bss_info(padapter, precv_frame, pbss) == _SUCCESS) {
+					struct beacon_keys recv_beacon;
+
+					update_network(&(pmlmepriv->cur_network.network), pbss, padapter, _TRUE);
+					rtw_get_bcn_info(&(pmlmepriv->cur_network));
+
+					/* update bcn keys */
+					if (rtw_get_bcn_keys(padapter, pframe, len, &recv_beacon) == _TRUE) {
+						RTW_INFO("%s: beacon keys ready\n", __func__);
+						_rtw_memcpy(&pmlmepriv->cur_beacon_keys,
+							&recv_beacon, sizeof(recv_beacon));
+						pmlmepriv->new_beacon_cnts = 0;
+					} else {
+						RTW_ERR("%s: get beacon keys failed\n", __func__);
+						_rtw_memset(&pmlmepriv->cur_beacon_keys, 0, sizeof(recv_beacon));
+						pmlmepriv->new_beacon_cnts = 0;
+					}
+				}
+				rtw_mfree((u8 *)pbss, sizeof(WLAN_BSSID_EX));
+			}
+
+			/* 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);
+
+			/* reset for adaptive_early_32k */
+			pmlmeext->adaptive_tsf_done = _FALSE;
+			pmlmeext->DrvBcnEarly = 0xff;
+			pmlmeext->DrvBcnTimeOut = 0xff;
+			pmlmeext->bcn_cnt = 0;
+			_rtw_memset(pmlmeext->bcn_delay_cnt, 0, sizeof(pmlmeext->bcn_delay_cnt));
+			_rtw_memset(pmlmeext->bcn_delay_ratio, 0, sizeof(pmlmeext->bcn_delay_ratio));
+
+			/* Comment by YiWei , in wifi p2p spec the "3.3 P2P Power Management" , "These mechanisms are available in a P2P Group in which only P2P Devices are associated." */
+			/* process_p2p_ps_ie(padapter, (pframe + WLAN_HDR_A3_LEN), (len - WLAN_HDR_A3_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, get_addr2_ptr(pframe));
+			if (psta != NULL) {
+#ifdef CONFIG_PATCH_JOIN_WRONG_CHANNEL
+				/* Merge from 8712 FW code */
+				if (cmp_pkt_chnl_diff(padapter, pframe, len) != 0) {
+					/* join wrong channel, deauth and reconnect           */
+					issue_deauth(padapter, (&(pmlmeinfo->network))->MacAddress, WLAN_REASON_DEAUTH_LEAVING);
+
+					report_del_sta_event(padapter, (&(pmlmeinfo->network))->MacAddress, WLAN_REASON_JOIN_WRONG_CHANNEL, _TRUE, _FALSE);
+					pmlmeinfo->state &= (~WIFI_FW_ASSOC_SUCCESS);
+					return _SUCCESS;
+				}
+#endif /* CONFIG_PATCH_JOIN_WRONG_CHANNEL */
+
+				ret = rtw_check_bcn_info(padapter, pframe, len);
+				if (!ret) {
+					RTW_PRINT("ap has changed, disconnect now\n ");
+					receive_disconnect(padapter, pmlmeinfo->network.MacAddress , 0, _FALSE);
+					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) {
+					/* RTW_INFO("update_bcn_info\n"); */
+					update_beacon_info(padapter, pframe, len, psta);
+				}
+
+				pmlmepriv->cur_network_scanned->network.Rssi = precv_frame->u.hdr.attrib.phy_info.RecvSignalPower;
+
+				adaptive_early_32k(pmlmeext, pframe, len);
+
+
+				process_p2p_ps_ie(padapter, (pframe + WLAN_HDR_A3_LEN), (len - WLAN_HDR_A3_LEN));
+
+				if (pmlmeext->en_hw_update_tsf)
+					rtw_enable_hw_update_tsf_cmd(padapter);
+
+			}
+
+		} else if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) {
+			_irqL irqL;
+			u8 rate_set[16];
+			u8 rate_num = 0;
+
+			psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(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);
+
+				if (pmlmeext->en_hw_update_tsf)
+					rtw_enable_hw_update_tsf_cmd(padapter);
+			} else {
+				rtw_ies_get_supported_rate(pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_, len - WLAN_HDR_A3_LEN - _BEACON_IE_OFFSET_, rate_set, &rate_num);
+				if (rate_num == 0) {
+					RTW_INFO(FUNC_ADPT_FMT" RX beacon with no supported rate\n", FUNC_ADPT_ARG(padapter));
+					goto _END_ONBEACON_;
+				}
+
+				psta = rtw_alloc_stainfo(pstapriv, get_addr2_ptr(pframe));
+				if (psta == NULL) {
+					RTW_INFO(FUNC_ADPT_FMT" Exceed the upper limit of supported clients\n", FUNC_ADPT_ARG(padapter));
+					goto _END_ONBEACON_;
+				}
+
+				psta->expire_to = pstapriv->adhoc_expire_to;
+
+				_rtw_memcpy(psta->bssrateset, rate_set, rate_num);
+				psta->bssratelen = rate_num;
+
+				/* update TSF Value */
+				update_TSF(pmlmeext, pframe, len);
+
+				/* report sta add event */
+				report_add_sta_event(padapter, get_addr2_ptr(pframe));
+			}
+		}
+	}
+
+_END_ONBEACON_:
+
+	return _SUCCESS;
+
+}
+
+unsigned int OnAuth(_adapter *padapter, union recv_frame *precv_frame)
+{
+	_irqL irqL;
+	unsigned int	auth_mode, seq, ie_len;
+	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->u.hdr.rx_data;
+	uint len = precv_frame->u.hdr.len;
+	u8	offset = 0;
+
+
+	if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)
+		return _FAIL;
+
+	RTW_INFO("+OnAuth\n");
+
+	sa = get_addr2_ptr(pframe);
+
+	auth_mode = psecuritypriv->dot11AuthAlgrthm;
+
+	if (GetPrivacy(pframe)) {
+		u8	*iv;
+		struct rx_pkt_attrib	*prxattrib = &(precv_frame->u.hdr.attrib);
+
+		prxattrib->hdrlen = WLAN_HDR_A3_LEN;
+		prxattrib->encrypt = _WEP40_;
+
+		iv = pframe + prxattrib->hdrlen;
+		prxattrib->key_index = ((iv[3] >> 6) & 0x3);
+
+		prxattrib->iv_len = 4;
+		prxattrib->icv_len = 4;
+
+		rtw_wep_decrypt(padapter, (u8 *)precv_frame);
+
+		offset = 4;
+	}
+
+	algorithm = le16_to_cpu(*(u16 *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset));
+	seq	= le16_to_cpu(*(u16 *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 2));
+
+	RTW_INFO("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 */
+		RTW_INFO("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) == _FALSE) {
+		status = _STATS_UNABLE_HANDLE_STA_;
+		goto auth_fail;
+	}
+
+	pstat = rtw_get_stainfo(pstapriv, sa);
+	if (pstat == NULL) {
+
+		/* allocate a new one */
+		RTW_INFO("going to alloc stainfo for sa="MAC_FMT"\n",  MAC_ARG(sa));
+		pstat = rtw_alloc_stainfo(pstapriv, sa);
+		if (pstat == NULL) {
+			RTW_INFO(" 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;
+
+		/* pstat->flags = 0; */
+		/* pstat->capability = 0; */
+	} else {
+		{
+
+			_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+			if (rtw_is_list_empty(&pstat->asoc_list) == _FALSE) {
+				rtw_list_delete(&pstat->asoc_list);
+				pstapriv->asoc_list_cnt--;
+				if (pstat->expire_to > 0)
+					;/* TODO: STA re_auth within expire_to */
+			}
+			_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+			if (seq == 1)
+				; /* TODO: STA re_auth and auth timeout */
+
+		}
+	}
+
+	{
+		_enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
+		if (rtw_is_list_empty(&pstat->auth_list)) {
+
+			rtw_list_insert_tail(&pstat->auth_list, &pstapriv->auth_list);
+			pstapriv->auth_list_cnt++;
+		}
+		_exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
+	}
+
+	if (pstat->auth_seq == 0)
+		pstat->expire_to = pstapriv->auth_to;
+
+	if ((pstat->auth_seq + 1) != seq) {
+		RTW_INFO("(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 || auth_mode == 3)) {
+		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 {
+			RTW_INFO("(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... */
+
+			/* get_random_bytes((void *)pstat->chg_txt, 128); */ /* TODO: */
+			_rtw_memset((void *)pstat->chg_txt, 78, 128);
+			{
+				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... */
+			RTW_INFO("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)) {
+				RTW_INFO("auth rejected because challenge failure!(1)\n");
+				status = _STATS_CHALLENGE_FAIL_;
+				goto auth_fail;
+			}
+
+			if (_rtw_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 {
+				RTW_INFO("auth rejected because challenge failure!\n");
+				status = _STATS_CHALLENGE_FAIL_;
+				goto auth_fail;
+			}
+		} else {
+			RTW_INFO("(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;
+
+	issue_auth(padapter, pstat, (unsigned short)(_STATS_SUCCESSFUL_));
+
+	if ((pstat->state & WIFI_FW_AUTH_SUCCESS) || (pstat->state & WIFI_FW_ASSOC_SUCCESS))
+		pstat->auth_seq = 0;
+
+	return _SUCCESS;
+
+auth_fail:
+
+	if (pstat)
+		rtw_free_stainfo(padapter , pstat);
+
+	pstat = &stat;
+	_rtw_memset((char *)pstat, '\0', sizeof(stat));
+	pstat->auth_seq = 2;
+	_rtw_memcpy(pstat->hwaddr, sa, 6);
+
+	issue_auth(padapter, pstat, (unsigned short)status);
+
+	return _FAIL;
+
+}
+
+unsigned int OnAuthClient(_adapter *padapter, union recv_frame *precv_frame)
+{
+	unsigned int	seq, len, status, algthm, 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->u.hdr.rx_data;
+	uint pkt_len = precv_frame->u.hdr.len;
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	/* check A1 matches or not */
+	if (!_rtw_memcmp(adapter_mac_addr(padapter), get_da(pframe), ETH_ALEN))
+		return _SUCCESS;
+
+	if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE))
+		return _SUCCESS;
+
+	offset = (GetPrivacy(pframe)) ? 4 : 0;
+
+	algthm	= le16_to_cpu(*(unsigned short *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset));
+	seq	= le16_to_cpu(*(unsigned short *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 2));
+	status	= le16_to_cpu(*(unsigned short *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 4));
+
+	if (status != 0) {
+		RTW_INFO("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;
+			/* pmlmeinfo->reauth_count = 0; */
+		}
+
+		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) {
+				/* RTW_INFO("marc: no challenge text?\n"); */
+				goto authclnt_fail;
+			}
+
+			_rtw_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, or 802.11r FTAA system */
+			go2asoc = 1;
+		}
+	} else if (seq == 4) {
+		if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared)
+			go2asoc = 1;
+		else
+			goto authclnt_fail;
+	} else {
+		/* this is also illegal */
+		/* RTW_INFO("marc: clnt auth failed due to illegal seq=%x\n", seq); */
+		goto authclnt_fail;
+	}
+
+	if (go2asoc) {
+
+		RTW_PRINT("auth success, start assoc\n");
+		start_clnt_assoc(padapter);
+		return _SUCCESS;
+	}
+
+authclnt_fail:
+
+	/* pmlmeinfo->state &= ~(WIFI_FW_AUTH_STATE); */
+
+	return _FAIL;
+
+}
+
+unsigned int OnAssocReq(_adapter *padapter, union recv_frame *precv_frame)
+{
+	_irqL irqL;
+	u16 capab_info, listen_interval;
+	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;
+	u8 rate_set[16];
+	u8 rate_num;
+	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);
+	WLAN_BSSID_EX	*cur = &(pmlmeinfo->network);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint pkt_len = precv_frame->u.hdr.len;
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	u8 p2p_status_code = P2P_STATUS_SUCCESS;
+	u8 *p2pie;
+	u32 p2pielen = 0;
+
+
+	if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)
+		return _FAIL;
+
+	frame_type = get_frame_sub_type(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) {
+		RTW_INFO("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
+			 "\n", reassoc, (unsigned long)pkt_len);
+		return _FAIL;
+	}
+
+	pstat = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe));
+	if (pstat == (struct sta_info *)NULL) {
+		status = _RSON_CLS2_;
+		goto asoc_class2_error;
+	}
+
+	capab_info = RTW_GET_LE16(pframe + WLAN_HDR_A3_LEN);
+	/* capab_info = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN));	 */
+	/* listen_interval = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN+2)); */
+	listen_interval = RTW_GET_LE16(pframe + WLAN_HDR_A3_LEN + 2);
+
+	left = pkt_len - (IEEE80211_3ADDR_LEN + ie_offset);
+	pos = pframe + (IEEE80211_3ADDR_LEN + ie_offset);
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	/* 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) {
+		RTW_INFO("STA " MAC_FMT " sent invalid association request\n",
+			 MAC_ARG(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 (!_rtw_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;
+
+	rtw_ies_get_supported_rate(pframe + WLAN_HDR_A3_LEN + ie_offset, pkt_len - WLAN_HDR_A3_LEN - ie_offset, rate_set, &rate_num);
+	if (rate_num == 0) {
+		RTW_INFO(FUNC_ADPT_FMT" RX assoc-req with no supported rate\n", FUNC_ADPT_ARG(padapter));
+		status = _STATS_FAILURE_;
+		goto OnAssocReqFail;
+	}
+	_rtw_memcpy(pstat->bssrateset, rate_set, rate_num);
+	pstat->bssratelen = rate_num;
+	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;
+	_rtw_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 (hapd->conf->wps_state && wpa_ie == NULL) { */ /* todo: to check ap if supporting WPS */
+	if (wpa_ie == NULL) {
+		if (elems.wps_ie) {
+			RTW_INFO("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 {
+			RTW_INFO("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) {
+					RTW_INFO("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) {
+			RTW_INFO("STA " MAC_FMT ": WPA/RSN IE in association "
+				"request, but AP don't support WPA/RSN\n", MAC_ARG(pstat->hwaddr));
+
+			status = WLAN_STATUS_INVALID_IE;
+
+			goto OnAssocReqFail;
+
+		}
+
+		if (elems.wps_ie) {
+			RTW_INFO("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)
+			_rtw_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 (_rtw_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;
+		}
+	}
+
+	if (pmlmepriv->htpriv.ht_option == _FALSE)
+		goto bypass_ht_chk;
+
+	/* save HT capabilities in the sta object */
+	_rtw_memset(&pstat->htpriv.ht_cap, 0, sizeof(struct rtw_ieee80211_ht_cap));
+	if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct rtw_ieee80211_ht_cap)) {
+		pstat->flags |= WLAN_STA_HT;
+
+		pstat->flags |= WLAN_STA_WME;
+
+		_rtw_memcpy(&pstat->htpriv.ht_cap, elems.ht_capabilities, sizeof(struct rtw_ieee80211_ht_cap));
+
+	} else
+		pstat->flags &= ~WLAN_STA_HT;
+bypass_ht_chk:
+
+	if ((pmlmepriv->htpriv.ht_option == _FALSE) && (pstat->flags & WLAN_STA_HT)) {
+		rtw_warn_on(1);
+		status = _STATS_FAILURE_;
+		goto OnAssocReqFail;
+	}
+
+	if (pmlmepriv->vhtpriv.vht_option == _FALSE)
+		goto bypass_vht_chk;
+
+	_rtw_memset(&pstat->vhtpriv, 0, sizeof(struct vht_priv));
+	if (elems.vht_capabilities && elems.vht_capabilities_len == 12) {
+		pstat->flags |= WLAN_STA_VHT;
+
+		_rtw_memcpy(pstat->vhtpriv.vht_cap, elems.vht_capabilities, 12);
+
+		if (elems.vht_op_mode_notify && elems.vht_op_mode_notify_len == 1)
+			_rtw_memcpy(&pstat->vhtpriv.vht_op_mode_notify, elems.vht_op_mode_notify, 1);
+		else /* for Frame without Operating Mode notify ie; default: 80M */
+			pstat->vhtpriv.vht_op_mode_notify = CHANNEL_WIDTH_80;
+	} else
+		pstat->flags &= ~WLAN_STA_VHT;
+bypass_vht_chk:
+
+	if ((pmlmepriv->vhtpriv.vht_option == _FALSE) && (pstat->flags & WLAN_STA_VHT)) {
+		rtw_warn_on(1);
+		status = _STATS_FAILURE_;
+		goto OnAssocReqFail;
+	}
+
+	if (((pstat->flags & WLAN_STA_HT) || (pstat->flags & WLAN_STA_VHT)) &&
+	    ((pstat->wpa2_pairwise_cipher & WPA_CIPHER_TKIP) ||
+	     (pstat->wpa_pairwise_cipher & WPA_CIPHER_TKIP))) {
+
+		RTW_INFO("(V)HT: " MAC_FMT " tried to use TKIP with (V)HT association\n", MAC_ARG(pstat->hwaddr));
+
+		pstat->flags &= ~WLAN_STA_HT;
+		pstat->flags &= ~WLAN_STA_VHT;
+		/*status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
+		  * goto OnAssocReqFail;
+		*/
+	}
+
+	/*
+	 * if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) */ /* ? */
+	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;
+
+	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;
+			}
+		}
+		rtw_process_wfd_ies(padapter, pframe + WLAN_HDR_A3_LEN + ie_offset, pkt_len - WLAN_HDR_A3_LEN - ie_offset, __func__);
+	}
+	pstat->p2p_status_code = p2p_status_code;
+
+	/* 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)
+		RTW_INFO("  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) {
+				if (pstat->aid > pstapriv->max_num_sta) {
+					pstat->aid = 0;
+
+					RTW_INFO("  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;
+					RTW_INFO("allocate new AID = (%d)\n", pstat->aid);
+					break;
+				}
+			}
+		}
+	}
+
+	pstat->state &= (~WIFI_FW_ASSOC_STATE);
+	pstat->state |= WIFI_FW_ASSOC_SUCCESS;
+	/* RTW_INFO("==================%s, %d,  (%x), bpairwise_key_installed=%d, MAC:"MAC_FMT"\n"
+	, __func__, __LINE__, pstat->state, pstat->bpairwise_key_installed, MAC_ARG(pstat->hwaddr)); */
+	{
+		_enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
+		if (!rtw_is_list_empty(&pstat->auth_list)) {
+			rtw_list_delete(&pstat->auth_list);
+			pstapriv->auth_list_cnt--;
+		}
+		_exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
+
+		_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+		if (rtw_is_list_empty(&pstat->asoc_list)) {
+			pstat->expire_to = pstapriv->expire_to;
+			rtw_list_insert_tail(&pstat->asoc_list, &pstapriv->asoc_list);
+			pstapriv->asoc_list_cnt++;
+		}
+		_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	}
+
+	/* now the station is qualified to join our BSS...	 */
+	if (pstat && (pstat->state & WIFI_FW_ASSOC_SUCCESS) && (_STATS_SUCCESSFUL_ == status)) {
+		{
+			/* .1 bss_cap_update & sta_info_update */
+			bss_cap_update_on_sta_join(padapter, pstat);
+			sta_info_update(padapter, pstat);
+		}
+		/* .2 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);
+
+		{
+			/* .3-(1) report sta add event */
+			report_add_sta_event(padapter, pstat->hwaddr);
+		}
+	}
+
+	return _SUCCESS;
+
+asoc_class2_error:
+
+	issue_deauth(padapter, (void *)get_addr2_ptr(pframe), status);
+
+	return _FAIL;
+
+OnAssocReqFail:
+
+	pstat->aid = 0;
+	if (frame_type == WIFI_ASSOCREQ)
+		issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP);
+	else
+		issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP);
+
+
+	return _FAIL;
+
+}
+
+unsigned int OnAssocRsp(_adapter *padapter, union recv_frame *precv_frame)
+{
+	uint i;
+	int res;
+	unsigned short	status;
+	PNDIS_802_11_VARIABLE_IEs	pIE;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	/* WLAN_BSSID_EX 		*cur_network = &(pmlmeinfo->network); */
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint pkt_len = precv_frame->u.hdr.len;
+	PNDIS_802_11_VARIABLE_IEs	pWapiIE = NULL;
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	/* check A1 matches or not */
+	if (!_rtw_memcmp(adapter_mac_addr(padapter), 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(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN + 2));
+	if (status > 0) {
+		RTW_INFO("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(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN));
+
+	/* set slot time */
+	pmlmeinfo->slotTime = (pmlmeinfo->capability & BIT(10)) ? 9 : 20;
+
+	/* AID */
+	res = pmlmeinfo->aid = (int)(le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN + 4)) & 0x3fff);
+
+	/* 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 = (PNDIS_802_11_VARIABLE_IEs)(pframe + i);
+
+		switch (pIE->ElementID) {
+		case _VENDOR_SPECIFIC_IE_:
+			if (_rtw_memcmp(pIE->data, WMM_PARA_OUI, 6))	/* WMM */
+				WMM_param_handler(padapter, pIE);
+			else if (_rtw_memcmp(pIE->data, WFD_OUI, 4))		/* WFD */
+				rtw_process_wfd_ie(padapter, (u8 *)pIE, pIE->Length, __func__);
+			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 EID_VHTCapability:
+			VHT_caps_handler(padapter, pIE);
+			break;
+
+		case EID_VHTOperation:
+			VHT_operation_handler(padapter, pIE);
+			break;
+
+		case _ERPINFO_IE_:
+			ERP_IE_handler(padapter, pIE);
+			break;
+		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(_adapter *padapter, union 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->u.hdr.rx_data;
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	/* check A3 */
+	if (!(_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)))
+		return _SUCCESS;
+
+	RTW_INFO(FUNC_ADPT_FMT" - Start to Disconnect\n", FUNC_ADPT_ARG(padapter));
+
+	if (pwdinfo->rx_invitereq_info.scan_op_ch_only) {
+		_cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey);
+		_set_timer(&pwdinfo->reset_ch_sitesurvey, 10);
+	}
+
+	reason = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN));
+
+	rtw_lock_rx_suspend_timeout(8000);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) {
+		_irqL irqL;
+		struct sta_info *psta;
+		struct sta_priv *pstapriv = &padapter->stapriv;
+
+		/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);		 */
+		/* rtw_free_stainfo(padapter, psta); */
+		/* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);		 */
+
+		RTW_PRINT(FUNC_ADPT_FMT" reason=%u, ta=%pM\n"
+			, FUNC_ADPT_ARG(padapter), reason, get_addr2_ptr(pframe));
+
+		psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe));
+		if (psta) {
+			u8 updated = _FALSE;
+
+			_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+			if (rtw_is_list_empty(&psta->asoc_list) == _FALSE) {
+				rtw_list_delete(&psta->asoc_list);
+				pstapriv->asoc_list_cnt--;
+				updated = ap_free_sta(padapter, psta, _FALSE, reason, _TRUE);
+
+			}
+			_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+			associated_clients_update(padapter, updated, STA_INFO_UPDATE_ALL);
+		}
+
+		return _SUCCESS;
+	} else
+	{
+		int	ignore_received_deauth = 0;
+
+		/*	Commented by Albert 20130604 */
+		/*	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;
+			}
+		}
+
+		RTW_PRINT(FUNC_ADPT_FMT" reason=%u, ta=%pM, ignore=%d\n"
+			, FUNC_ADPT_ARG(padapter), reason, get_addr2_ptr(pframe), ignore_received_deauth);
+
+		if (0 == ignore_received_deauth)
+			receive_disconnect(padapter, get_addr2_ptr(pframe), reason, _FALSE);
+	}
+	pmlmepriv->LinkDetectInfo.bBusyTraffic = _FALSE;
+	return _SUCCESS;
+
+}
+
+unsigned int OnDisassoc(_adapter *padapter, union 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->u.hdr.rx_data;
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	/* check A3 */
+	if (!(_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)))
+		return _SUCCESS;
+
+	RTW_INFO(FUNC_ADPT_FMT" - Start to Disconnect\n", FUNC_ADPT_ARG(padapter));
+
+	if (pwdinfo->rx_invitereq_info.scan_op_ch_only) {
+		_cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey);
+		_set_timer(&pwdinfo->reset_ch_sitesurvey, 10);
+	}
+
+	reason = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN));
+
+	rtw_lock_rx_suspend_timeout(8000);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) {
+		_irqL irqL;
+		struct sta_info *psta;
+		struct sta_priv *pstapriv = &padapter->stapriv;
+
+		/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);	 */
+		/* rtw_free_stainfo(padapter, psta); */
+		/* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);		 */
+
+		RTW_PRINT(FUNC_ADPT_FMT" reason=%u, ta=%pM\n"
+			, FUNC_ADPT_ARG(padapter), reason, get_addr2_ptr(pframe));
+
+		psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe));
+		if (psta) {
+			u8 updated = _FALSE;
+
+			_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+			if (rtw_is_list_empty(&psta->asoc_list) == _FALSE) {
+				rtw_list_delete(&psta->asoc_list);
+				pstapriv->asoc_list_cnt--;
+				updated = ap_free_sta(padapter, psta, _FALSE, reason, _TRUE);
+
+			}
+			_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+			associated_clients_update(padapter, updated, STA_INFO_UPDATE_ALL);
+		}
+
+		return _SUCCESS;
+	} else
+	{
+		RTW_PRINT(FUNC_ADPT_FMT" reason=%u, ta=%pM\n"
+			, FUNC_ADPT_ARG(padapter), reason, get_addr2_ptr(pframe));
+
+		receive_disconnect(padapter, get_addr2_ptr(pframe), reason, _FALSE);
+	}
+	pmlmepriv->LinkDetectInfo.bBusyTraffic = _FALSE;
+	return _SUCCESS;
+
+}
+
+unsigned int OnAtim(_adapter *padapter, union recv_frame *precv_frame)
+{
+	RTW_INFO("%s\n", __FUNCTION__);
+	return _SUCCESS;
+}
+
+unsigned int on_action_spct_ch_switch(_adapter *padapter, struct sta_info *psta, u8 *ies, uint ies_len)
+{
+	unsigned int ret = _FAIL;
+	struct mlme_ext_priv *mlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(mlmeext->mlmext_info);
+
+	if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) {
+		ret = _SUCCESS;
+		goto exit;
+	}
+
+	if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) {
+
+		int ch_switch_mode = -1, ch = -1, ch_switch_cnt = -1;
+		int ch_offset = -1;
+		u8 bwmode;
+		struct ieee80211_info_element *ie;
+
+		RTW_INFO(FUNC_NDEV_FMT" from "MAC_FMT"\n",
+			FUNC_NDEV_ARG(padapter->pnetdev), MAC_ARG(psta->hwaddr));
+
+		for_each_ie(ie, ies, ies_len) {
+			if (ie->id == WLAN_EID_CHANNEL_SWITCH) {
+				ch_switch_mode = ie->data[0];
+				ch = ie->data[1];
+				ch_switch_cnt = ie->data[2];
+				RTW_INFO("ch_switch_mode:%d, ch:%d, ch_switch_cnt:%d\n",
+					 ch_switch_mode, ch, ch_switch_cnt);
+			} else if (ie->id == WLAN_EID_SECONDARY_CHANNEL_OFFSET) {
+				ch_offset = secondary_ch_offset_to_hal_ch_offset(ie->data[0]);
+				RTW_INFO("ch_offset:%d\n", ch_offset);
+			}
+		}
+
+		if (ch == -1)
+			return _SUCCESS;
+
+		if (ch_offset == -1)
+			bwmode = mlmeext->cur_bwmode;
+		else
+			bwmode = (ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) ?
+				 CHANNEL_WIDTH_20 : CHANNEL_WIDTH_40;
+
+		ch_offset = (ch_offset == -1) ? mlmeext->cur_ch_offset : ch_offset;
+
+		/* todo:
+		 * 1. the decision of channel switching
+		 * 2. things after channel switching
+		 */
+
+		ret = rtw_set_ch_cmd(padapter, ch, bwmode, ch_offset, _TRUE);
+	}
+
+exit:
+	return ret;
+}
+
+unsigned int on_action_spct(_adapter *padapter, union recv_frame *precv_frame)
+{
+	unsigned int ret = _FAIL;
+	struct sta_info *psta = NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint frame_len = precv_frame->u.hdr.len;
+	u8 *frame_body = (u8 *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+	u8 category;
+	u8 action;
+
+	RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
+
+	psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe));
+
+	if (!psta)
+		goto exit;
+
+	category = frame_body[0];
+	if (category != RTW_WLAN_CATEGORY_SPECTRUM_MGMT)
+		goto exit;
+
+	action = frame_body[1];
+
+exit:
+	return ret;
+}
+
+unsigned int OnAction_qos(_adapter *padapter, union recv_frame *precv_frame)
+{
+	return _SUCCESS;
+}
+
+unsigned int OnAction_dls(_adapter *padapter, union recv_frame *precv_frame)
+{
+	return _SUCCESS;
+}
+
+/**
+ * rtw_rx_ampdu_size - Get the target RX AMPDU buffer size for the specific @adapter
+ * @adapter: the adapter to get target RX AMPDU buffer size
+ *
+ * Returns: the target RX AMPDU buffer size
+ */
+u8 rtw_rx_ampdu_size(_adapter *adapter)
+{
+	u8 size;
+	HT_CAP_AMPDU_FACTOR max_rx_ampdu_factor;
+
+	if (rtw_btcoex_IsBTCoexCtrlAMPDUSize(adapter) == _TRUE) {
+		size = rtw_btcoex_GetAMPDUSize(adapter);
+		goto exit;
+	}
+
+	/* for scan */
+	if (!mlmeext_chk_scan_state(&adapter->mlmeextpriv, SCAN_DISABLE)
+	    && !mlmeext_chk_scan_state(&adapter->mlmeextpriv, SCAN_COMPLETE)
+	    && adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_size != RX_AMPDU_SIZE_INVALID
+	   ) {
+		size = adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_size;
+		goto exit;
+	}
+
+	/* default value based on max_rx_ampdu_factor */
+	if (adapter->driver_rx_ampdu_factor != 0xFF)
+		max_rx_ampdu_factor = (HT_CAP_AMPDU_FACTOR)adapter->driver_rx_ampdu_factor;
+	else
+		rtw_hal_get_def_var(adapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor);
+	
+	/* In Maximum A-MPDU Length Exponent subfield of A-MPDU Parameters field of HT Capabilities element,
+		the unit of max_rx_ampdu_factor are octets. 8K, 16K, 32K, 64K is right.
+		But the buffer size subfield of Block Ack Parameter Set field in ADDBA action frame indicates
+		the number of buffers available for this particular TID. Each buffer is equal to max. size of 
+		MSDU or AMSDU. 
+		The size variable means how many MSDUs or AMSDUs, it's not Kbytes.
+	*/
+	if (MAX_AMPDU_FACTOR_64K == max_rx_ampdu_factor)
+		size = 64;
+	else if (MAX_AMPDU_FACTOR_32K == max_rx_ampdu_factor)
+		size = 32;
+	else if (MAX_AMPDU_FACTOR_16K == max_rx_ampdu_factor)
+		size = 16;
+	else if (MAX_AMPDU_FACTOR_8K == max_rx_ampdu_factor)
+		size = 8;
+	else
+		size = 64;
+
+exit:
+
+	if (size > 127)
+		size = 127;
+
+	return size;
+}
+
+/**
+ * rtw_rx_ampdu_is_accept - Get the permission if RX AMPDU should be set up for the specific @adapter
+ * @adapter: the adapter to get the permission if RX AMPDU should be set up
+ *
+ * Returns: accept or not
+ */
+bool rtw_rx_ampdu_is_accept(_adapter *adapter)
+{
+	bool accept;
+
+	if (adapter->fix_rx_ampdu_accept != RX_AMPDU_ACCEPT_INVALID) {
+		accept = adapter->fix_rx_ampdu_accept;
+		goto exit;
+	}
+
+	if (rtw_btcoex_IsBTCoexRejectAMPDU(adapter) == _TRUE) {
+		accept = _FALSE;
+		goto exit;
+	}
+
+	/* for scan */
+	if (!mlmeext_chk_scan_state(&adapter->mlmeextpriv, SCAN_DISABLE)
+	    && !mlmeext_chk_scan_state(&adapter->mlmeextpriv, SCAN_COMPLETE)
+	    && adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_accept != RX_AMPDU_ACCEPT_INVALID
+	   ) {
+		accept = adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_accept;
+		goto exit;
+	}
+
+	/* default value for other cases */
+	accept = adapter->mlmeextpriv.mlmext_info.bAcceptAddbaReq;
+
+exit:
+	return accept;
+}
+
+/**
+ * rtw_rx_ampdu_set_size - Set the target RX AMPDU buffer size for the specific @adapter and specific @reason
+ * @adapter: the adapter to set target RX AMPDU buffer size
+ * @size: the target RX AMPDU buffer size to set
+ * @reason: reason for the target RX AMPDU buffer size setting
+ *
+ * Returns: whether the target RX AMPDU buffer size is changed
+ */
+bool rtw_rx_ampdu_set_size(_adapter *adapter, u8 size, u8 reason)
+{
+	bool is_adj = _FALSE;
+	struct mlme_ext_priv *mlmeext;
+	struct mlme_ext_info *mlmeinfo;
+
+	mlmeext = &adapter->mlmeextpriv;
+	mlmeinfo = &mlmeext->mlmext_info;
+
+	if (reason == RX_AMPDU_DRV_FIXED) {
+		if (adapter->fix_rx_ampdu_size != size) {
+			adapter->fix_rx_ampdu_size = size;
+			is_adj = _TRUE;
+			RTW_INFO(FUNC_ADPT_FMT" fix_rx_ampdu_size:%u\n", FUNC_ADPT_ARG(adapter), size);
+		}
+	} else if (reason == RX_AMPDU_DRV_SCAN) {
+		struct ss_res *ss = &adapter->mlmeextpriv.sitesurvey_res;
+
+		if (ss->rx_ampdu_size != size) {
+			ss->rx_ampdu_size = size;
+			is_adj = _TRUE;
+			RTW_INFO(FUNC_ADPT_FMT" ss.rx_ampdu_size:%u\n", FUNC_ADPT_ARG(adapter), size);
+		}
+	}
+
+	return is_adj;
+}
+
+/**
+ * rtw_rx_ampdu_set_accept - Set the permission if RX AMPDU should be set up for the specific @adapter and specific @reason
+ * @adapter: the adapter to set if RX AMPDU should be set up
+ * @accept: if RX AMPDU should be set up
+ * @reason: reason for the permission if RX AMPDU should be set up
+ *
+ * Returns: whether the permission if RX AMPDU should be set up is changed
+ */
+bool rtw_rx_ampdu_set_accept(_adapter *adapter, u8 accept, u8 reason)
+{
+	bool is_adj = _FALSE;
+	struct mlme_ext_priv *mlmeext;
+	struct mlme_ext_info *mlmeinfo;
+
+	mlmeext = &adapter->mlmeextpriv;
+	mlmeinfo = &mlmeext->mlmext_info;
+
+	if (reason == RX_AMPDU_DRV_FIXED) {
+		if (adapter->fix_rx_ampdu_accept != accept) {
+			adapter->fix_rx_ampdu_accept = accept;
+			is_adj = _TRUE;
+			RTW_INFO(FUNC_ADPT_FMT" fix_rx_ampdu_accept:%u\n", FUNC_ADPT_ARG(adapter), accept);
+		}
+	} else if (reason == RX_AMPDU_DRV_SCAN) {
+		if (adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_accept != accept) {
+			adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_accept = accept;
+			is_adj = _TRUE;
+			RTW_INFO(FUNC_ADPT_FMT" ss.rx_ampdu_accept:%u\n", FUNC_ADPT_ARG(adapter), accept);
+		}
+	}
+
+	return is_adj;
+}
+
+/**
+ * rx_ampdu_apply_sta_tid - Apply RX AMPDU setting to the specific @sta and @tid
+ * @adapter: the adapter to which @sta belongs
+ * @sta: the sta to be checked
+ * @tid: the tid to be checked
+ * @accept: the target permission if RX AMPDU should be set up
+ * @size: the target RX AMPDU buffer size
+ *
+ * Returns:
+ * 0: no canceled
+ * 1: canceled by no permission
+ * 2: canceled by different buffer size
+ * 3: canceled by potential mismatched status
+ *
+ * Blocking function, may sleep
+ */
+u8 rx_ampdu_apply_sta_tid(_adapter *adapter, struct sta_info *sta, u8 tid, u8 accept, u8 size)
+{
+	u8 ret = 0;
+	struct recv_reorder_ctrl *reorder_ctl = &sta->recvreorder_ctrl[tid];
+
+	if (reorder_ctl->enable == _FALSE) {
+		if (reorder_ctl->ampdu_size != RX_AMPDU_SIZE_INVALID) {
+			send_delba_sta_tid_wait_ack(adapter, 0, sta, tid, 1);
+			ret = 3;
+		}
+		goto exit;
+	}
+
+	if (accept == _FALSE) {
+		send_delba_sta_tid_wait_ack(adapter, 0, sta, tid, 0);
+		ret = 1;
+	} else if (reorder_ctl->ampdu_size != size) {
+		send_delba_sta_tid_wait_ack(adapter, 0, sta, tid, 0);
+		ret = 2;
+	}
+
+exit:
+	return ret;
+}
+
+u8 rx_ampdu_size_sta_limit(_adapter *adapter, struct sta_info *sta)
+{
+	u8 sz_limit = 0xFF;
+
+	struct registry_priv *regsty = adapter_to_regsty(adapter);
+	struct mlme_priv *mlme = &adapter->mlmepriv;
+	struct mlme_ext_info *mlmeinfo = &adapter->mlmeextpriv.mlmext_info;
+	s8 nss = -1;
+	u8 bw = rtw_min(sta->bw_mode, adapter->mlmeextpriv.cur_bwmode);
+
+	if (is_supported_vht(sta->wireless_mode)) {
+		nss = rtw_min(rtw_vht_mcsmap_to_nss(mlme->vhtpriv.vht_mcs_map)
+				, rtw_vht_mcsmap_to_nss(sta->vhtpriv.vht_mcs_map));
+	} else
+	if (is_supported_ht(sta->wireless_mode)) {
+		nss = rtw_min(rtw_ht_mcsset_to_nss(mlmeinfo->HT_caps.u.HT_cap_element.MCS_rate)
+				, rtw_ht_mcsset_to_nss(sta->htpriv.ht_cap.supp_mcs_set));
+	}
+
+	if (nss >= 1)
+		sz_limit = regsty->rx_ampdu_sz_limit_by_nss_bw[nss - 1][bw];
+
+	return sz_limit;
+}
+
+/**
+ * rx_ampdu_apply_sta - Apply RX AMPDU setting to the specific @sta
+ * @adapter: the adapter to which @sta belongs
+ * @sta: the sta to be checked
+ * @accept: the target permission if RX AMPDU should be set up
+ * @size: the target RX AMPDU buffer size
+ *
+ * Returns: number of the RX AMPDU assciation canceled for applying current target setting
+ *
+ * Blocking function, may sleep
+ */
+u8 rx_ampdu_apply_sta(_adapter *adapter, struct sta_info *sta, u8 accept, u8 size)
+{
+	u8 change_cnt = 0;
+	int i;
+
+	for (i = 0; i < TID_NUM; i++) {
+		if (rx_ampdu_apply_sta_tid(adapter, sta, i, accept, size) != 0)
+			change_cnt++;
+	}
+
+	return change_cnt;
+}
+
+/**
+ * rtw_rx_ampdu_apply - Apply the current target RX AMPDU setting for the specific @adapter
+ * @adapter: the adapter to be applied
+ *
+ * Returns: number of the RX AMPDU assciation canceled for applying current target setting
+ */
+u16 rtw_rx_ampdu_apply(_adapter *adapter)
+{
+	u16 adj_cnt = 0;
+	struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+	struct sta_info *sta;
+	u8 accept = rtw_rx_ampdu_is_accept(adapter);
+	u8 size;
+
+	if (adapter->fix_rx_ampdu_size != RX_AMPDU_SIZE_INVALID)
+		size = adapter->fix_rx_ampdu_size;
+	else
+		size = rtw_rx_ampdu_size(adapter);
+
+	if (mlmeext_msr(mlmeext) == WIFI_FW_STATION_STATE) {
+		sta = rtw_get_stainfo(&adapter->stapriv, get_bssid(&adapter->mlmepriv));
+		if (sta) {
+			u8 sta_size = size;
+
+			if (adapter->fix_rx_ampdu_size == RX_AMPDU_SIZE_INVALID)
+				sta_size = rtw_min(size, rx_ampdu_size_sta_limit(adapter, sta));
+			adj_cnt += rx_ampdu_apply_sta(adapter, sta, accept, sta_size);
+		}
+
+	} else if (mlmeext_msr(mlmeext) == WIFI_FW_AP_STATE) {
+		_irqL irqL;
+		_list *phead, *plist;
+		u8 peer_num = 0;
+		char peers[NUM_STA];
+		struct sta_priv *pstapriv = &adapter->stapriv;
+		int i;
+
+		_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+		phead = &pstapriv->asoc_list;
+		plist = get_next(phead);
+
+		while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+			int stainfo_offset;
+
+			sta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+			plist = get_next(plist);
+
+			stainfo_offset = rtw_stainfo_offset(pstapriv, sta);
+			if (stainfo_offset_valid(stainfo_offset))
+				peers[peer_num++] = stainfo_offset;
+		}
+
+		_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+		for (i = 0; i < peer_num; i++) {
+			sta = rtw_get_stainfo_by_offset(pstapriv, peers[i]);
+			if (sta) {
+				u8 sta_size = size;
+
+				if (adapter->fix_rx_ampdu_size == RX_AMPDU_SIZE_INVALID)
+					sta_size = rtw_min(size, rx_ampdu_size_sta_limit(adapter, sta));
+				adj_cnt += rx_ampdu_apply_sta(adapter, sta, accept, sta_size);
+			}
+		}
+	}
+
+	return adj_cnt;
+}
+
+unsigned int OnAction_back(_adapter *padapter, union 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->u.hdr.rx_data;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct registry_priv *pregpriv = &padapter->registrypriv;
+
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	/* check RA matches or not	 */
+	if (!_rtw_memcmp(adapter_mac_addr(padapter), GetAddr1Ptr(pframe), ETH_ALEN))
+		return _SUCCESS;
+
+	if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)
+		if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS))
+			return _SUCCESS;
+
+	addr = get_addr2_ptr(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];
+		RTW_INFO("%s, action=%d\n", __FUNCTION__, action);
+		switch (action) {
+		case RTW_WLAN_ACTION_ADDBA_REQ: /* ADDBA request */
+
+			_rtw_memcpy(&(pmlmeinfo->ADDBA_req), &(frame_body[2]), sizeof(struct ADDBA_request));
+			/* process_addba_req(padapter, (u8*)&(pmlmeinfo->ADDBA_req), GetAddr3Ptr(pframe)); */
+			process_addba_req(padapter, (u8 *)&(pmlmeinfo->ADDBA_req), addr);
+
+			break;
+
+		case RTW_WLAN_ACTION_ADDBA_RESP: /* ADDBA response */
+
+			/* status = frame_body[3] | (frame_body[4] << 8); */ /* endian issue */
+			status = RTW_GET_LE16(&frame_body[3]);
+			tid = ((frame_body[5] >> 2) & 0x7);
+			if (status == 0) {
+				/* successful					 */
+				RTW_INFO("agg_enable for TID=%d\n", tid);
+				psta->htpriv.agg_enable_bitmap |= 1 << tid;
+				psta->htpriv.candidate_tid_bitmap &= ~BIT(tid);
+				/* amsdu in ampdu */
+				if (pregpriv->tx_ampdu_amsdu == 0)
+					psta->htpriv.tx_amsdu_enable = _FALSE;
+				else if (pregpriv->tx_ampdu_amsdu == 1)
+					psta->htpriv.tx_amsdu_enable = _TRUE;
+				else {
+					if (frame_body[5] & 1)
+						psta->htpriv.tx_amsdu_enable = _TRUE;
+				}
+			} else
+				psta->htpriv.agg_enable_bitmap &= ~BIT(tid);
+
+			if (psta->state & WIFI_STA_ALIVE_CHK_STATE) {
+				RTW_INFO("%s alive check - rx ADDBA response\n", __func__);
+				psta->htpriv.agg_enable_bitmap &= ~BIT(tid);
+				psta->expire_to = pstapriv->expire_to;
+				psta->state ^= WIFI_STA_ALIVE_CHK_STATE;
+			}
+
+			/* RTW_INFO("marc: ADDBA RSP: %x\n", pmlmeinfo->agg_enable_bitmap); */
+			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 = frame_body[4] | (frame_body[5] << 8); */
+				reason_code = RTW_GET_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->ampdu_size = RX_AMPDU_SIZE_INVALID;
+			}
+
+			RTW_INFO("%s(): DELBA: %x(%x)\n", __FUNCTION__, pmlmeinfo->agg_enable_bitmap, reason_code);
+			/* todo: how to notify the host while receiving DELETE BA */
+			break;
+
+		default:
+			break;
+		}
+	}
+	return _SUCCESS;
+}
+
+
+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(_adapter *padapter, u8 *raddr)
+{
+
+	unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+	u8			action = P2P_PUB_ACTION_ACTION;
+	u32			p2poui = cpu_to_be32(P2POUI);
+	u8			oui_subtype = P2P_GO_NEGO_REQ;
+	u8			wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 };
+	u8			wpsielen = 0, p2pielen = 0, i;
+	u8			channel_cnt_24g = 0, channel_cnt_5gl = 0, channel_cnt_5gh = 0;
+	u16			len_channellist_attr = 0;
+	u32					wfdielen = 0;
+
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	RTW_INFO("[%s] In\n", __FUNCTION__);
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_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;
+
+	_rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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 */
+	*(u32 *)(wpsie) = cpu_to_be32(WPSOUI);
+	wpsielen += 4;
+
+	/*	WPS version */
+	/*	Type: */
+	*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+	wpsielen += 2;
+
+	/*	Value: */
+	wpsie[wpsielen++] = WPS_VERSION_1;	/*	Version 1.0 */
+
+	/*	Device Password ID */
+	/*	Type: */
+	*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+	wpsielen += 2;
+
+	/*	Value: */
+
+	if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN)
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC);
+	else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN)
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC);
+	else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC)
+		*(u16 *)(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: */
+	*(u16 *)(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: */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Todo the tie breaker bit. */
+	p2pie[p2pielen++] = ((pwdinfo->intent << 1) &  0xFE);
+
+	/*	Configuration Timeout */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT;
+
+	/*	Length: */
+	*(u16 *)(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: */
+	*(u16 *)(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: */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Availability Period */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+	p2pielen += 2;
+
+	/*	Availability Interval */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+	p2pielen += 2;
+
+	/*	Intended P2P Interface Address */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_INTENDED_IF_ADDR;
+
+	/*	Length: */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
+	p2pielen += 2;
+
+	/*	Value: */
+	_rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), 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);
+
+
+	*(u16 *)(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) */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	P2P Device Address */
+	_rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), 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);
+
+	p2pielen += 2;
+
+	/*	Primary Device Type */
+	/*	Category ID */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+	p2pielen += 2;
+
+	/*	OUI */
+	*(u32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI);
+	p2pielen += 4;
+
+	/*	Sub Category ID */
+	*(u16 *)(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: */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+	p2pielen += 2;
+
+	/*	Length: */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	_rtw_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: */
+	*(u16 *)(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 */
+	if (pwdinfo->operating_channel <= 14) {
+		/*	Operating Class */
+		p2pie[p2pielen++] = 0x51;
+	} else if ((pwdinfo->operating_channel >= 36) && (pwdinfo->operating_channel <= 48)) {
+		/*	Operating Class */
+		p2pie[p2pielen++] = 0x73;
+	} else {
+		/*	Operating Class */
+		p2pie[p2pielen++] = 0x7c;
+	}
+
+	/*	Channel Number */
+	p2pie[p2pielen++] = pwdinfo->operating_channel;	/*	operating channel number */
+
+	pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen);
+
+	wfdielen = build_nego_req_wfd_ie(pwdinfo, pframe);
+	pframe += wfdielen;
+	pattrib->pktlen += wfdielen;
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+
+}
+
+void issue_p2p_GO_response(_adapter *padapter, u8 *raddr, u8 *frame_body, uint len, u8 result)
+{
+
+	unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+	u8			action = P2P_PUB_ACTION_ACTION;
+	u32			p2poui = cpu_to_be32(P2POUI);
+	u8			oui_subtype = P2P_GO_NEGO_RESP;
+	u8			wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 };
+	u8			p2pielen = 0, i;
+	uint			wpsielen = 0;
+	u16			wps_devicepassword_id = 0x0000;
+	uint			wps_devicepassword_id_len = 0;
+	u8			channel_cnt_24g = 0, channel_cnt_5gl = 0, channel_cnt_5gh;
+	u16			len_channellist_attr = 0;
+
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+
+	u32					wfdielen = 0;
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	RTW_INFO("[%s] In, result = %d\n", __FUNCTION__,  result);
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_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;
+
+	_rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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 *) &wps_devicepassword_id, &wps_devicepassword_id_len);
+	wps_devicepassword_id = be16_to_cpu(wps_devicepassword_id);
+
+	_rtw_memset(wpsie, 0x00, 255);
+	wpsielen = 0;
+
+	/*	WPS Section */
+	wpsielen = 0;
+	/*	WPS OUI */
+	*(u32 *)(wpsie) = cpu_to_be32(WPSOUI);
+	wpsielen += 4;
+
+	/*	WPS version */
+	/*	Type: */
+	*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+	wpsielen += 2;
+
+	/*	Value: */
+	wpsie[wpsielen++] = WPS_VERSION_1;	/*	Version 1.0 */
+
+	/*	Device Password ID */
+	/*	Type: */
+	*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+	wpsielen += 2;
+
+	/*	Value: */
+	if (wps_devicepassword_id == WPS_DPID_USER_SPEC)
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC);
+	else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC)
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC);
+	else
+		*(u16 *)(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 (_rtw_memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) {
+		if (wps_devicepassword_id == WPS_DPID_USER_SPEC)
+			_rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3);
+		else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC)
+			_rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3);
+		else
+			_rtw_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: */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001);
+	p2pielen += 2;
+
+	/*	Value: */
+	p2pie[p2pielen++] = result;
+
+	/*	P2P Capability */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+	/*	Length: */
+	*(u16 *)(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 negotation 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: */
+	*(u16 *)(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: */
+	*(u16 *)(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: */
+	*(u16 *)(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 */
+	if (pwdinfo->operating_channel <= 14) {
+		/*	Operating Class */
+		p2pie[p2pielen++] = 0x51;
+	} else if ((pwdinfo->operating_channel >= 36) && (pwdinfo->operating_channel <= 48)) {
+		/*	Operating Class */
+		p2pie[p2pielen++] = 0x73;
+	} else {
+		/*	Operating Class */
+		p2pie[p2pielen++] = 0x7c;
+	}
+
+	/*	Channel Number */
+	p2pie[p2pielen++] = pwdinfo->operating_channel;	/*	operating channel number */
+
+	/*	Intended P2P Interface Address	 */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_INTENDED_IF_ADDR;
+
+	/*	Length: */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
+	p2pielen += 2;
+
+	/*	Value: */
+	_rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), 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);
+
+	*(u16 *)(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) */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	P2P Device Address */
+	_rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), 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);
+
+	p2pielen += 2;
+
+	/*	Primary Device Type */
+	/*	Category ID */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+	p2pielen += 2;
+
+	/*	OUI */
+	*(u32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI);
+	p2pielen += 4;
+
+	/*	Sub Category ID */
+	*(u16 *)(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: */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+	p2pielen += 2;
+
+	/*	Length: */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	_rtw_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: */
+		*(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen);
+		p2pielen += 2;
+
+		/*	Value: */
+		/*	p2P Device Address */
+		_rtw_memcpy(p2pie + p2pielen , pwdinfo->device_addr, ETH_ALEN);
+		p2pielen += ETH_ALEN;
+
+		/*	SSID */
+		_rtw_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);
+
+	wfdielen = build_nego_resp_wfd_ie(pwdinfo, pframe);
+	pframe += wfdielen;
+	pattrib->pktlen += wfdielen;
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+
+}
+
+void issue_p2p_GO_confirm(_adapter *padapter, u8 *raddr, u8 result)
+{
+
+	unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+	u8			action = P2P_PUB_ACTION_ACTION;
+	u32			p2poui = cpu_to_be32(P2POUI);
+	u8			oui_subtype = P2P_GO_NEGO_CONF;
+	u8			wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 };
+	u8			wpsielen = 0, p2pielen = 0;
+
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	u32					wfdielen = 0;
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	RTW_INFO("[%s] In\n", __FUNCTION__);
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_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;
+
+	_rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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: */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001);
+	p2pielen += 2;
+
+	/*	Value: */
+	p2pie[p2pielen++] = result;
+
+	/*	P2P Capability */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+	/*	Length: */
+	*(u16 *)(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: */
+	*(u16 *)(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)) {
+		if (pwdinfo->peer_operating_ch <= 14) {
+			/*	Operating Class */
+			p2pie[p2pielen++] = 0x51;
+		} else if ((pwdinfo->peer_operating_ch >= 36) && (pwdinfo->peer_operating_ch <= 48)) {
+			/*	Operating Class */
+			p2pie[p2pielen++] = 0x73;
+		} else {
+			/*	Operating Class */
+			p2pie[p2pielen++] = 0x7c;
+		}
+
+		p2pie[p2pielen++] = pwdinfo->peer_operating_ch;
+	} else {
+		if (pwdinfo->operating_channel <= 14) {
+			/*	Operating Class */
+			p2pie[p2pielen++] = 0x51;
+		} else if ((pwdinfo->operating_channel >= 36) && (pwdinfo->operating_channel <= 48)) {
+			/*	Operating Class */
+			p2pie[p2pielen++] = 0x73;
+		} else {
+			/*	Operating Class */
+			p2pie[p2pielen++] = 0x7c;
+		}
+
+		/*	Channel Number */
+		p2pie[p2pielen++] = pwdinfo->operating_channel;		/*	Use the listen channel as the operating channel */
+	}
+
+	/*	Channel List */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
+
+	*(u16 *)(p2pie + p2pielen) = 6;
+	p2pielen += 2;
+
+	/*	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;
+
+	/*	Value: */
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
+		if (pwdinfo->peer_operating_ch <= 14) {
+			/*	Operating Class */
+			p2pie[p2pielen++] = 0x51;
+		} else if ((pwdinfo->peer_operating_ch >= 36) && (pwdinfo->peer_operating_ch <= 48)) {
+			/*	Operating Class */
+			p2pie[p2pielen++] = 0x73;
+		} else {
+			/*	Operating Class */
+			p2pie[p2pielen++] = 0x7c;
+		}
+		p2pie[p2pielen++] = 1;
+		p2pie[p2pielen++] = pwdinfo->peer_operating_ch;
+	} else {
+		if (pwdinfo->operating_channel <= 14) {
+			/*	Operating Class */
+			p2pie[p2pielen++] = 0x51;
+		} else if ((pwdinfo->operating_channel >= 36) && (pwdinfo->operating_channel <= 48)) {
+			/*	Operating Class */
+			p2pie[p2pielen++] = 0x73;
+		} else {
+			/*	Operating Class */
+			p2pie[p2pielen++] = 0x7c;
+		}
+
+		/*	Channel Number */
+		p2pie[p2pielen++] = 1;
+		p2pie[p2pielen++] = pwdinfo->operating_channel;		/*	Use the listen channel as the operating channel */
+	}
+
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+		/*	Group ID Attribute */
+		/*	Type: */
+		p2pie[p2pielen++] = P2P_ATTR_GROUP_ID;
+
+		/*	Length: */
+		*(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen);
+		p2pielen += 2;
+
+		/*	Value: */
+		/*	p2P Device Address */
+		_rtw_memcpy(p2pie + p2pielen , pwdinfo->device_addr, ETH_ALEN);
+		p2pielen += ETH_ALEN;
+
+		/*	SSID */
+		_rtw_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);
+
+	wfdielen = build_nego_confirm_wfd_ie(pwdinfo, pframe);
+	pframe += wfdielen;
+	pattrib->pktlen += wfdielen;
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+
+}
+
+void issue_p2p_invitation_request(_adapter *padapter, u8 *raddr)
+{
+
+	unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+	u8			action = P2P_PUB_ACTION_ACTION;
+	u32			p2poui = cpu_to_be32(P2POUI);
+	u8			oui_subtype = P2P_INVIT_REQ;
+	u8			p2pie[255] = { 0x00 };
+	u8			p2pielen = 0, i;
+	u8			dialogToken = 3;
+	u8			channel_cnt_24g = 0, channel_cnt_5gl = 0, channel_cnt_5gh = 0;
+	u16			len_channellist_attr = 0;
+	u32					wfdielen = 0;
+
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_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;
+
+	_rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, raddr,  ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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: */
+	*(u16 *)(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: */
+	*(u16 *)(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: */
+	*(u16 *)(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 */
+	if (pwdinfo->invitereq_info.operating_ch <= 14)
+		p2pie[p2pielen++] = 0x51;
+	else if ((pwdinfo->invitereq_info.operating_ch >= 36) && (pwdinfo->invitereq_info.operating_ch <= 48))
+		p2pie[p2pielen++] = 0x73;
+	else
+		p2pie[p2pielen++] = 0x7c;
+
+	/*	Channel Number */
+	p2pie[p2pielen++] = pwdinfo->invitereq_info.operating_ch;	/*	operating channel number */
+
+	if (_rtw_memcmp(adapter_mac_addr(padapter), pwdinfo->invitereq_info.go_bssid, ETH_ALEN)) {
+		/*	P2P Group BSSID */
+		/*	Type: */
+		p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID;
+
+		/*	Length: */
+		*(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
+		p2pielen += 2;
+
+		/*	Value: */
+		/*	P2P Device Address for GO */
+		_rtw_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);
+
+	*(u16 *)(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: */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_le16(6 + pwdinfo->invitereq_info.ssidlen);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	P2P Device Address for GO */
+	_rtw_memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN);
+	p2pielen += ETH_ALEN;
+
+	/*	SSID */
+	_rtw_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) */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	P2P Device Address */
+	_rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), ETH_ALEN);
+	p2pielen += ETH_ALEN;
+
+	/*	Config Method */
+	/*	This field should be big endian. Noted by P2P specification. */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY);
+	p2pielen += 2;
+
+	/*	Primary Device Type */
+	/*	Category ID */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+	p2pielen += 2;
+
+	/*	OUI */
+	*(u32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI);
+	p2pielen += 4;
+
+	/*	Sub Category ID */
+	*(u16 *)(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: */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+	p2pielen += 2;
+
+	/*	Length: */
+	*(u16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	_rtw_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);
+
+	wfdielen = build_invitation_req_wfd_ie(pwdinfo, pframe);
+	pframe += wfdielen;
+	pattrib->pktlen += wfdielen;
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+
+}
+
+void issue_p2p_invitation_response(_adapter *padapter, u8 *raddr, u8 dialogToken, u8 status_code)
+{
+
+	unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+	u8			action = P2P_PUB_ACTION_ACTION;
+	u32			p2poui = cpu_to_be32(P2POUI);
+	u8			oui_subtype = P2P_INVIT_RESP;
+	u8			p2pie[255] = { 0x00 };
+	u8			p2pielen = 0, i;
+	u8			channel_cnt_24g = 0, channel_cnt_5gl = 0, channel_cnt_5gh = 0;
+	u16			len_channellist_attr = 0;
+	u32					wfdielen = 0;
+
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_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;
+
+	_rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, raddr,  ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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: */
+	*(u16 *)(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: */
+	*(u16 *)(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: */
+			*(u16 *)(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: */
+			*(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
+			p2pielen += 2;
+
+			/*	Value: */
+			/*	P2P Device Address for GO */
+			_rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), 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);
+
+		*(u16 *)(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);
+
+	wfdielen = build_invitation_resp_wfd_ie(pwdinfo, pframe);
+	pframe += wfdielen;
+	pattrib->pktlen += wfdielen;
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+
+}
+
+void issue_p2p_provision_request(_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;
+	u32			p2poui = cpu_to_be32(P2POUI);
+	u8			oui_subtype = P2P_PROVISION_DISC_REQ;
+	u8			wpsie[100] = { 0x00 };
+	u8			wpsielen = 0;
+	u32			p2pielen = 0;
+	u32					wfdielen = 0;
+
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	RTW_INFO("[%s] In\n", __FUNCTION__);
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_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;
+
+	_rtw_memcpy(pwlanhdr->addr1, pdev_raddr, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, pdev_raddr, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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 */
+	*(u32 *)(wpsie) = cpu_to_be32(WPSOUI);
+	wpsielen += 4;
+
+	/*	WPS version */
+	/*	Type: */
+	*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+	wpsielen += 2;
+
+	/*	Value: */
+	wpsie[wpsielen++] = WPS_VERSION_1;	/*	Version 1.0 */
+
+	/*	Config Method */
+	/*	Type: */
+	*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+	wpsielen += 2;
+
+	/*	Value: */
+	*(u16 *)(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);
+
+	wfdielen = build_provdisc_req_wfd_ie(pwdinfo, pframe);
+	pframe += wfdielen;
+	pattrib->pktlen += wfdielen;
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+
+}
+
+u8 is_matched_in_profilelist(u8 *peermacaddr, struct profile_info *profileinfo)
+{
+	u8 i, match_result = 0;
+
+	RTW_INFO("[%s] peermac = %.2X %.2X %.2X %.2X %.2X %.2X\n", __FUNCTION__,
+		peermacaddr[0], peermacaddr[1], peermacaddr[2], peermacaddr[3], peermacaddr[4], peermacaddr[5]);
+
+	for (i = 0; i < P2P_MAX_PERSISTENT_GROUP_NUM; i++, profileinfo++) {
+		RTW_INFO("[%s] profileinfo_mac = %.2X %.2X %.2X %.2X %.2X %.2X\n", __FUNCTION__,
+			profileinfo->peermac[0], profileinfo->peermac[1], profileinfo->peermac[2], profileinfo->peermac[3], profileinfo->peermac[4], profileinfo->peermac[5]);
+		if (_rtw_memcmp(peermacaddr, profileinfo->peermac, ETH_ALEN)) {
+			match_result = 1;
+			RTW_INFO("[%s] Match!\n", __FUNCTION__);
+			break;
+		}
+	}
+
+	return match_result ;
+}
+
+void issue_probersp_p2p(_adapter *padapter, unsigned char *da)
+{
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	unsigned char					*mac;
+	struct xmit_priv	*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	/* WLAN_BSSID_EX 		*cur_network = &(pmlmeinfo->network); */
+	u16					beacon_interval = 100;
+	u16					capInfo = 0;
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	u8					wpsie[255] = { 0x00 };
+	u32					wpsielen = 0, p2pielen = 0;
+	u32					wfdielen = 0;
+
+	/* RTW_INFO("%s\n", __FUNCTION__); */
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	if (IS_CCK_RATE(pattrib->rate)) {
+		/* force OFDM 6M rate */
+		pattrib->rate = MGN_6M;
+		pattrib->raid = rtw_get_mgntframe_raid(padapter, WIRELESS_11G);
+	}
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	mac = adapter_mac_addr(padapter);
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+	_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
+
+	/*	Use the device address for BSSID field.	 */
+	_rtw_memcpy(pwlanhdr->addr3, mac, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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 */
+	_rtw_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;
+
+	_rtw_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 */
+		*(u32 *)(wpsie) = cpu_to_be32(WPSOUI);
+		wpsielen += 4;
+
+		/*	WPS version */
+		/*	Type: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+		wpsielen += 2;
+
+		/*	Value: */
+		wpsie[wpsielen++] = WPS_VERSION_1;	/*	Version 1.0 */
+
+		/*	WiFi Simple Config State */
+		/*	Type: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SIMPLE_CONF_STATE);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+		wpsielen += 2;
+
+		/*	Value: */
+		wpsie[wpsielen++] = WPS_WSC_STATE_NOT_CONFIG;	/*	Not Configured. */
+
+		/*	Response Type */
+		/*	Type: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_RESP_TYPE);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+		wpsielen += 2;
+
+		/*	Value: */
+		wpsie[wpsielen++] = WPS_RESPONSE_TYPE_8021X;
+
+		/*	UUID-E */
+		/*	Type: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0010);
+		wpsielen += 2;
+
+		/*	Value: */
+		if (pwdinfo->external_uuid == 0) {
+			_rtw_memset(wpsie + wpsielen, 0x0, 16);
+			_rtw_memcpy(wpsie + wpsielen, mac, ETH_ALEN);
+		} else
+			_rtw_memcpy(wpsie + wpsielen, pwdinfo->uuid, 0x10);
+		wpsielen += 0x10;
+
+		/*	Manufacturer */
+		/*	Type: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MANUFACTURER);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0007);
+		wpsielen += 2;
+
+		/*	Value: */
+		_rtw_memcpy(wpsie + wpsielen, "Realtek", 7);
+		wpsielen += 7;
+
+		/*	Model Name */
+		/*	Type: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NAME);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0006);
+		wpsielen += 2;
+
+		/*	Value: */
+		_rtw_memcpy(wpsie + wpsielen, "8192CU", 6);
+		wpsielen += 6;
+
+		/*	Model Number */
+		/*	Type: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NUMBER);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+		wpsielen += 2;
+
+		/*	Value: */
+		wpsie[wpsielen++] = 0x31;		/*	character 1 */
+
+		/*	Serial Number */
+		/*	Type: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SERIAL_NUMBER);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(ETH_ALEN);
+		wpsielen += 2;
+
+		/*	Value: */
+		_rtw_memcpy(wpsie + wpsielen, "123456" , ETH_ALEN);
+		wpsielen += ETH_ALEN;
+
+		/*	Primary Device Type */
+		/*	Type: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008);
+		wpsielen += 2;
+
+		/*	Value: */
+		/*	Category ID */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+		wpsielen += 2;
+
+		/*	OUI */
+		*(u32 *)(wpsie + wpsielen) = cpu_to_be32(WPSOUI);
+		wpsielen += 4;
+
+		/*	Sub Category ID */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+		wpsielen += 2;
+
+		/*	Device Name */
+		/*	Type: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->device_name_len);
+		wpsielen += 2;
+
+		/*	Value: */
+		_rtw_memcpy(wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len);
+		wpsielen += pwdinfo->device_name_len;
+
+		/*	Config Method */
+		/*	Type: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+		wpsielen += 2;
+
+		/*	Value: */
+		*(u16 *)(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;
+	}
+
+	wfdielen = rtw_append_probe_resp_wfd_ie(padapter, pframe);
+	pframe += wfdielen;
+	pattrib->pktlen += wfdielen;
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+
+}
+
+int _issue_probereq_p2p(_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;
+	unsigned short		*fctrl;
+	unsigned char			*mac;
+	unsigned char			bssrate[NumRates];
+	struct xmit_priv		*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	int	bssrate_len = 0;
+	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;
+	u32					wfdielen = 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);
+
+	if (IS_CCK_RATE(pattrib->rate)) {
+		/* force OFDM 6M rate */
+		pattrib->rate = MGN_6M;
+		pattrib->raid = rtw_get_mgntframe_raid(padapter, WIRELESS_11G);
+	}
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	mac = adapter_mac_addr(padapter);
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	if (da) {
+		_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+		_rtw_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. */
+			_rtw_memcpy(pwlanhdr->addr1, pwdinfo->p2p_peer_interface_addr, ETH_ALEN);
+			_rtw_memcpy(pwlanhdr->addr3, pwdinfo->p2p_peer_interface_addr, ETH_ALEN);
+		} else {
+			/*	broadcast probe request frame */
+			_rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+			_rtw_memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN);
+		}
+	}
+	_rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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 */
+		*(u32 *)(wpsie) = cpu_to_be32(WPSOUI);
+		wpsielen += 4;
+
+		/*	WPS version */
+		/*	Type: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(u16 *)(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: */
+			*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E);
+			wpsielen += 2;
+
+			/*	Length: */
+			*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0010);
+			wpsielen += 2;
+
+			/*	Value: */
+			if (pwdinfo->external_uuid == 0) {
+				_rtw_memset(wpsie + wpsielen, 0x0, 16);
+				_rtw_memcpy(wpsie + wpsielen, mac, ETH_ALEN);
+			} else
+				_rtw_memcpy(wpsie + wpsielen, pwdinfo->uuid, 0x10);
+			wpsielen += 0x10;
+
+			/*	Config Method */
+			/*	Type: */
+			*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD);
+			wpsielen += 2;
+
+			/*	Length: */
+			*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+			wpsielen += 2;
+
+			/*	Value: */
+			*(u16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->supported_wps_cm);
+			wpsielen += 2;
+		}
+
+		/*	Device Name */
+		/*	Type: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->device_name_len);
+		wpsielen += 2;
+
+		/*	Value: */
+		_rtw_memcpy(wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len);
+		wpsielen += pwdinfo->device_name_len;
+
+		/*	Primary Device Type */
+		/*	Type: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008);
+		wpsielen += 2;
+
+		/*	Value: */
+		/*	Category ID */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_RTK_WIDI);
+		wpsielen += 2;
+
+		/*	OUI */
+		*(u32 *)(wpsie + wpsielen) = cpu_to_be32(WPSOUI);
+		wpsielen += 4;
+
+		/*	Sub Category ID */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_RTK_DMP);
+		wpsielen += 2;
+
+		/*	Device Password ID */
+		/*	Type: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+		wpsielen += 2;
+
+		/*	Value: */
+		*(u16 *)(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: */
+		*(u16 *)(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: */
+		*(u16 *)(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: */
+		*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004);
+		p2pielen += 2;
+
+		/*	Value: */
+		/*	Availability Period */
+		*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+		p2pielen += 2;
+
+		/*	Availability Interval */
+		*(u16 *)(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: */
+			*(u16 *)(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);
+
+	}
+
+	wfdielen = rtw_append_probe_req_wfd_ie(padapter, pframe);
+	pframe += wfdielen;
+	pattrib->pktlen += wfdielen;
+
+	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;
+}
+
+inline void issue_probereq_p2p(_adapter *adapter, u8 *da)
+{
+	_issue_probereq_p2p(adapter, da, _FALSE);
+}
+
+/*
+ * wait_ms == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT
+ * wait_ms > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX
+ * try_cnt means the maximal TX count to try
+ */
+int issue_probereq_p2p_ex(_adapter *adapter, u8 *da, int try_cnt, int wait_ms)
+{
+	int ret;
+	int i = 0;
+	u32 start = rtw_get_current_time();
+
+	do {
+		ret = _issue_probereq_p2p(adapter, da, wait_ms > 0 ? _TRUE : _FALSE);
+
+		i++;
+
+		if (RTW_CANNOT_RUN(adapter))
+			break;
+
+		if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+			rtw_msleep_os(wait_ms);
+
+	} while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+	return ret == _FAIL ? _FAIL : _SUCCESS;
+}
+
+
+s32 rtw_action_public_decache(union recv_frame *rframe, u8 token_offset)
+{
+	_adapter *adapter = rframe->u.hdr.adapter;
+	struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv);
+	u8 *frame = rframe->u.hdr.rx_data;
+	u16 seq_ctrl = ((rframe->u.hdr.attrib.seq_num & 0xffff) << 4) | (rframe->u.hdr.attrib.frag_num & 0xf);
+	u8 token = *(rframe->u.hdr.rx_data + sizeof(struct rtw_ieee80211_hdr_3addr) + token_offset);
+
+	if (GetRetry(frame)) {
+		if ((seq_ctrl == mlmeext->action_public_rxseq)
+		    && (token == mlmeext->action_public_dialog_token)
+		   ) {
+			RTW_INFO(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;
+		}
+	}
+
+	/* TODO: per sta seq & token */
+	mlmeext->action_public_rxseq = seq_ctrl;
+	mlmeext->action_public_dialog_token = token;
+
+	return _SUCCESS;
+}
+
+unsigned int on_action_public_p2p(union recv_frame *precv_frame)
+{
+	_adapter *padapter = precv_frame->u.hdr.adapter;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint len = precv_frame->u.hdr.len;
+	u8 *frame_body;
+	u8 *p2p_ie;
+	u32	p2p_ielen, wps_ielen;
+	struct	wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	u8	result = P2P_STATUS_SUCCESS;
+	u8	empty_addr[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+	u8 *merged_p2pie = NULL;
+	u32 merged_p2p_ielen = 0;
+
+	frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+
+	_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: {
+			RTW_INFO("[%s] Got GO Nego Req Frame\n", __FUNCTION__);
+			_rtw_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));
+				RTW_INFO("[%s] Restore the previous p2p state to %d\n", __FUNCTION__, 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 (_rtw_memcmp(pwdinfo->rx_prov_disc_info.peerDevAddr, empty_addr, ETH_ALEN))
+				_rtw_memcpy(pwdinfo->rx_prov_disc_info.peerDevAddr, get_addr2_ptr(pframe), ETH_ALEN);
+
+			result = process_p2p_group_negotation_req(pwdinfo, frame_body, len);
+			issue_p2p_GO_response(padapter, get_addr2_ptr(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: {
+			RTW_INFO("[%s] Got GO Nego Resp Frame\n", __FUNCTION__);
+
+			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, get_addr2_ptr(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.operation_ch[1] = 1;	/* Check whether GO is operating in channel 1; */
+						pwdinfo->p2p_info.operation_ch[2] = 6;	/* Check whether GO is operating in channel 6; */
+						pwdinfo->p2p_info.operation_ch[3] = 11;	/* Check whether GO is operating in channel 11; */
+						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
+				RTW_INFO("[%s] Skipped GO Nego Resp Frame (p2p_state != P2P_STATE_GONEGO_ING)\n", __FUNCTION__);
+
+			break;
+		}
+		case P2P_GO_NEGO_CONF: {
+			RTW_INFO("[%s] Got GO Nego Confirm Frame\n", __FUNCTION__);
+			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.operation_ch[1] = 1;	/* Check whether GO is operating in channel 1; */
+					pwdinfo->p2p_info.operation_ch[2] = 6;	/* Check whether GO is operating in channel 6; */
+					pwdinfo->p2p_info.operation_ch[3] = 11;	/* Check whether GO is operating in channel 11; */
+					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. */
+
+			RTW_INFO("[%s] Got invite request frame!\n", __FUNCTION__);
+			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;
+				int j = 0;
+
+				merged_p2p_ielen = rtw_get_p2p_merged_ies_len(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_);
+
+				merged_p2pie = rtw_zmalloc(merged_p2p_ielen + 2);	/* 2 is for EID and Length */
+				if (merged_p2pie == NULL) {
+					RTW_INFO("[%s] Malloc p2p ie fail\n", __FUNCTION__);
+					goto exit;
+				}
+				_rtw_memset(merged_p2pie, 0x00, merged_p2p_ielen);
+
+				merged_p2p_ielen = rtw_p2p_merge_ies(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, merged_p2pie);
+
+				rtw_get_p2p_attr_content(merged_p2pie, merged_p2p_ielen, P2P_ATTR_INVITATION_FLAGS, &invitation_flag, &attr_contentlen);
+				if (attr_contentlen) {
+
+					rtw_get_p2p_attr_content(merged_p2pie, merged_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) {
+						RTW_INFO("[%s] GO's BSSID = %.2X %.2X %.2X %.2X %.2X %.2X\n", __FUNCTION__,
+							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. */
+
+						_rtw_memset(&group_id, 0x00, sizeof(struct group_id_info));
+						rtw_get_p2p_attr_content(merged_p2pie, merged_p2p_ielen, P2P_ATTR_GROUP_ID, (u8 *) &group_id, &attr_contentlen);
+						if (attr_contentlen) {
+							if (_rtw_memcmp(group_id.go_device_addr, adapter_mac_addr(padapter), 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(merged_p2pie, merged_p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info,
+										&attr_contentlen)) {
+										if (rtw_chset_search_ch(padapter->mlmeextpriv.channel_set, (u32)operatingch_info[4]) >= 0) {
+											/*	The operating channel is acceptable for this device. */
+											pwdinfo->rx_invitereq_info.operation_ch[0] = operatingch_info[4];
+											pwdinfo->rx_invitereq_info.operation_ch[1] = 1;		/* Check whether GO is operating in channel 1; */
+											pwdinfo->rx_invitereq_info.operation_ch[2] = 6;		/* Check whether GO is operating in channel 6; */
+											pwdinfo->rx_invitereq_info.operation_ch[3] = 11;		/* Check whether GO is operating in channel 11; */
+											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 {
+							RTW_INFO("[%s] P2P Group ID Attribute NOT FOUND!\n", __FUNCTION__);
+							status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+						}
+					} else {
+						/*	Received the invitation to join a P2P group. */
+
+						_rtw_memset(&group_id, 0x00, sizeof(struct group_id_info));
+						rtw_get_p2p_attr_content(merged_p2pie, merged_p2p_ielen, P2P_ATTR_GROUP_ID, (u8 *) &group_id, &attr_contentlen);
+						if (attr_contentlen) {
+							if (_rtw_memcmp(group_id.go_device_addr, adapter_mac_addr(padapter), 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 */
+								_rtw_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 {
+							RTW_INFO("[%s] P2P Group ID Attribute NOT FOUND!\n", __FUNCTION__);
+							status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+						}
+					}
+				} else {
+					RTW_INFO("[%s] P2P Invitation Flags Attribute NOT FOUND!\n", __FUNCTION__);
+					status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+				}
+
+				RTW_INFO("[%s] status_code = %d\n", __FUNCTION__, status_code);
+
+				pwdinfo->inviteresp_info.token = frame_body[7];
+				issue_p2p_invitation_response(padapter, get_addr2_ptr(pframe), pwdinfo->inviteresp_info.token, status_code);
+				_set_timer(&pwdinfo->restore_p2p_state_timer, 3000);
+			}
+			break;
+		}
+		case P2P_INVIT_RESP: {
+			u8	attr_content = 0x00;
+			u32	attr_contentlen = 0;
+
+			RTW_INFO("[%s] Got invite response frame!\n", __FUNCTION__);
+			_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) {
+					RTW_INFO("[%s] Status = %d\n", __FUNCTION__, attr_content);
+					pwdinfo->invitereq_info.benable = _FALSE;
+
+					if (attr_content == P2P_STATUS_SUCCESS) {
+						if (_rtw_memcmp(pwdinfo->invitereq_info.go_bssid, adapter_mac_addr(padapter), 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:
+			RTW_INFO("[%s] Got Provisioning Discovery Request Frame\n", __FUNCTION__);
+			process_p2p_provdisc_req(pwdinfo, pframe, len);
+			_rtw_memcpy(pwdinfo->rx_prov_disc_info.peerDevAddr, get_addr2_ptr(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?? */
+			RTW_INFO("[%s] Got Provisioning Discovery Response Frame\n", __FUNCTION__);
+			/*	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;
+
+		}
+	}
+
+exit:
+
+	if (merged_p2pie)
+		rtw_mfree(merged_p2pie, merged_p2p_ielen + 2);
+	return _SUCCESS;
+}
+
+unsigned int on_action_public_vendor(union recv_frame *precv_frame)
+{
+	unsigned int ret = _FAIL;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint frame_len = precv_frame->u.hdr.len;
+	u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	if (_rtw_memcmp(frame_body + 2, P2P_OUI, 4) == _TRUE) {
+		if (rtw_action_public_decache(precv_frame, 7) == _FAIL)
+			goto exit;
+
+		if (!hal_chk_wl_func(precv_frame->u.hdr.adapter, WL_FUNC_MIRACAST))
+			rtw_rframe_del_wfd_ie(precv_frame, 8);
+
+		ret = on_action_public_p2p(precv_frame);
+	}
+
+exit:
+	return ret;
+}
+
+unsigned int on_action_public_default(union recv_frame *precv_frame, u8 action)
+{
+	unsigned int ret = _FAIL;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint frame_len = precv_frame->u.hdr.len;
+	u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
+	u8 token;
+	_adapter *adapter = precv_frame->u.hdr.adapter;
+	int cnt = 0;
+	char msg[64];
+
+	token = frame_body[2];
+
+	if (rtw_action_public_decache(precv_frame, 2) == _FAIL)
+		goto exit;
+
+
+	ret = _SUCCESS;
+
+exit:
+	return ret;
+}
+
+unsigned int on_action_public(_adapter *padapter, union recv_frame *precv_frame)
+{
+	unsigned int ret = _FAIL;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint frame_len = precv_frame->u.hdr.len;
+	u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
+	u8 category, action;
+
+	/* check RA matches or not */
+	if (!_rtw_memcmp(adapter_mac_addr(padapter), 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_BSSCOEXIST:
+		/*20/40 BSS Coexistence Management frame is a Public Action frame*/
+		if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE)
+			rtw_process_public_act_bsscoex(padapter, pframe, frame_len);
+		break;
+	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_ft(_adapter *padapter, union recv_frame *precv_frame)
+{
+	return _SUCCESS;
+}
+
+unsigned int OnAction_ht(_adapter *padapter, union recv_frame *precv_frame)
+{
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint frame_len = precv_frame->u.hdr.len;
+	u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
+	u8 category, action;
+
+	/* check RA matches or not */
+	if (!_rtw_memcmp(adapter_mac_addr(padapter), GetAddr1Ptr(pframe), ETH_ALEN))
+		goto exit;
+
+	category = frame_body[0];
+	if (category != RTW_WLAN_CATEGORY_HT)
+		goto exit;
+
+	action = frame_body[1];
+	switch (action) {
+	case RTW_WLAN_ACTION_HT_SM_PS:
+		if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE)
+			rtw_process_ht_action_smps(padapter, get_addr2_ptr(pframe), frame_body[2]);
+		break;
+	case RTW_WLAN_ACTION_HT_COMPRESS_BEAMFORMING:
+		break;
+	default:
+		break;
+	}
+
+exit:
+
+	return _SUCCESS;
+}
+
+unsigned int OnAction_wmm(_adapter *padapter, union recv_frame *precv_frame)
+{
+	return _SUCCESS;
+}
+
+unsigned int OnAction_vht(_adapter *padapter, union recv_frame *precv_frame)
+{
+	struct rx_pkt_attrib *prxattrib = &precv_frame->u.hdr.attrib;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint frame_len = precv_frame->u.hdr.len;
+	struct rtw_ieee80211_hdr_3addr *whdr = (struct rtw_ieee80211_hdr_3addr *)pframe;
+	u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
+	u8 category, action;
+	struct sta_info *psta = NULL;
+
+	/* check RA matches or not */
+	if (!_rtw_memcmp(adapter_mac_addr(padapter), GetAddr1Ptr(pframe), ETH_ALEN))
+		goto exit;
+
+	category = frame_body[0];
+	if (category != RTW_WLAN_CATEGORY_VHT)
+		goto exit;
+
+	action = frame_body[1];
+	switch (action) {
+	case RTW_WLAN_ACTION_VHT_COMPRESSED_BEAMFORMING:
+		break;
+	case RTW_WLAN_ACTION_VHT_OPMODE_NOTIFICATION:
+		/* CategoryCode(1) + ActionCode(1) + OpModeNotification(1) */
+		/* RTW_INFO("RTW_WLAN_ACTION_VHT_OPMODE_NOTIFICATION\n"); */
+		psta = rtw_get_stainfo(&padapter->stapriv, whdr->addr2);
+		if (psta)
+			rtw_process_vht_op_mode_notify(padapter, &frame_body[2], psta);
+		break;
+	case RTW_WLAN_ACTION_VHT_GROUPID_MANAGEMENT:
+		break;
+	default:
+		break;
+	}
+
+exit:
+
+	return _SUCCESS;
+}
+
+unsigned int OnAction_p2p(_adapter *padapter, union recv_frame *precv_frame)
+{
+	u8 *frame_body;
+	u8 category, OUI_Subtype, dialogToken = 0;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint len = precv_frame->u.hdr.len;
+	struct	wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+
+	/* check RA matches or not */
+	if (!_rtw_memcmp(adapter_mac_addr(padapter), GetAddr1Ptr(pframe), ETH_ALEN))
+		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 (cpu_to_be32(*((u32 *)(frame_body + 1))) != P2POUI)
+		return _SUCCESS;
+
+	{
+		len -= sizeof(struct rtw_ieee80211_hdr_3addr);
+		OUI_Subtype = frame_body[5];
+		dialogToken = frame_body[6];
+
+		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;
+
+		}
+	}
+
+	return _SUCCESS;
+
+}
+
+unsigned int OnAction(_adapter *padapter, union recv_frame *precv_frame)
+{
+	int i;
+	unsigned char	category;
+	struct action_handler *ptable;
+	unsigned char	*frame_body;
+	u8 *pframe = precv_frame->u.hdr.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(_adapter *padapter, union recv_frame *precv_frame)
+{
+
+	/* RTW_INFO("rcvd mgt frame(%x, %x)\n", (get_frame_sub_type(pframe) >> 4), *(unsigned int *)GetAddr1Ptr(pframe)); */
+	return _SUCCESS;
+}
+
+struct xmit_frame *_alloc_mgtxmitframe(struct xmit_priv *pxmitpriv, bool once)
+{
+	struct xmit_frame *pmgntframe;
+	struct xmit_buf *pxmitbuf;
+
+	if (once)
+		pmgntframe = rtw_alloc_xmitframe_once(pxmitpriv);
+	else
+		pmgntframe = rtw_alloc_xmitframe_ext(pxmitpriv);
+
+	if (pmgntframe == NULL) {
+		RTW_INFO(FUNC_ADPT_FMT" alloc xmitframe fail, once:%d\n", FUNC_ADPT_ARG(pxmitpriv->adapter), once);
+		goto exit;
+	}
+
+	pxmitbuf = rtw_alloc_xmitbuf_ext(pxmitpriv);
+	if (pxmitbuf == NULL) {
+		RTW_INFO(FUNC_ADPT_FMT" alloc xmitbuf fail\n", FUNC_ADPT_ARG(pxmitpriv->adapter));
+		rtw_free_xmitframe(pxmitpriv, pmgntframe);
+		pmgntframe = NULL;
+		goto exit;
+	}
+
+	pmgntframe->frame_tag = MGNT_FRAMETAG;
+	pmgntframe->pxmitbuf = pxmitbuf;
+	pmgntframe->buf_addr = pxmitbuf->pbuf;
+	pxmitbuf->priv_data = pmgntframe;
+
+exit:
+	return pmgntframe;
+
+}
+
+inline struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv)
+{
+	return _alloc_mgtxmitframe(pxmitpriv, _FALSE);
+}
+
+inline struct xmit_frame *alloc_mgtxmitframe_once(struct xmit_priv *pxmitpriv)
+{
+	return _alloc_mgtxmitframe(pxmitpriv, _TRUE);
+}
+
+/****************************************************************************
+
+Following are some TX fuctions for WiFi MLME
+
+*****************************************************************************/
+
+void update_mgnt_tx_rate(_adapter *padapter, u8 rate)
+{
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+
+	pmlmeext->tx_rate = rate;
+	/* RTW_INFO("%s(): rate = %x\n",__FUNCTION__, rate); */
+}
+
+void update_monitor_frame_attrib(_adapter *padapter, struct pkt_attrib *pattrib)
+{
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+	u8	wireless_mode;
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct xmit_priv		*pxmitpriv = &padapter->xmitpriv;
+	struct sta_info		*psta = NULL;
+	struct sta_priv		*pstapriv = &padapter->stapriv;
+	struct sta_info *pbcmc_sta = NULL;
+
+	psta = rtw_get_stainfo(pstapriv, pattrib->ra);
+	pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
+
+	pattrib->hdrlen = 24;
+	pattrib->nr_frags = 1;
+	pattrib->priority = 7;
+
+	if (pbcmc_sta)
+		pattrib->mac_id = pbcmc_sta->mac_id;
+	else {
+		pattrib->mac_id = 0;
+		RTW_INFO("mgmt use mac_id 0 will affect RA\n");
+	}
+	pattrib->qsel = QSLT_MGNT;
+
+	pattrib->pktlen = 0;
+
+	if (pmlmeext->tx_rate == IEEE80211_CCK_RATE_1MB)
+		wireless_mode = WIRELESS_11B;
+	else
+		wireless_mode = WIRELESS_11G;
+
+	pattrib->raid = rtw_get_mgntframe_raid(padapter, wireless_mode);
+	if (pHalData->rf_type == RF_1T1R)
+		pattrib->raid = RATEID_IDX_VHT_1SS;
+	else if (pHalData->rf_type == RF_2T2R || pHalData->rf_type == RF_2T4R)
+		pattrib->raid = RATEID_IDX_VHT_2SS;
+	else if (pHalData->rf_type == RF_3T3R)
+		pattrib->raid = RATEID_IDX_VHT_3SS;
+	else
+		pattrib->raid = RATEID_IDX_BGN_40M_1SS;
+
+	pattrib->rate = MGN_VHT1SS_MCS9;
+
+	pattrib->encrypt = _NO_PRIVACY_;
+	pattrib->bswenc = _FALSE;
+
+	pattrib->qos_en = _FALSE;
+	pattrib->ht_en = 1;
+	pattrib->bwmode = CHANNEL_WIDTH_20;
+	pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	pattrib->sgi = _FALSE;
+
+	pattrib->seqnum = pmlmeext->mgnt_seq;
+
+	pattrib->retry_ctrl = _TRUE;
+
+	pattrib->mbssid = 0;
+	pattrib->hw_ssn_sel = pxmitpriv->hw_ssn_seq_no;
+
+}
+
+void update_mgntframe_attrib(_adapter *padapter, struct pkt_attrib *pattrib)
+{
+	u8	wireless_mode;
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct xmit_priv		*pxmitpriv = &padapter->xmitpriv;
+	struct sta_info *pbcmc_sta = NULL;
+	/* _rtw_memset((u8 *)(pattrib), 0, sizeof(struct pkt_attrib)); */
+
+	pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
+
+	pattrib->hdrlen = 24;
+	pattrib->nr_frags = 1;
+	pattrib->priority = 7;
+
+	if (pbcmc_sta)
+		pattrib->mac_id = pbcmc_sta->mac_id;
+	else {
+		pattrib->mac_id = 1; /* use STA's BCMC sta-info macid */
+
+		if (MLME_IS_AP(padapter) || MLME_IS_GO(padapter))
+			RTW_INFO("%s-"ADPT_FMT" get bcmc sta_info fail,use MACID=1\n", __func__, ADPT_ARG(padapter));
+	}
+	pattrib->qsel = QSLT_MGNT;
+
+	pattrib->pktlen = 0;
+
+	if (IS_CCK_RATE(pmlmeext->tx_rate))
+		wireless_mode = WIRELESS_11B;
+	else
+		wireless_mode = WIRELESS_11G;
+	pattrib->raid =  rtw_get_mgntframe_raid(padapter, wireless_mode);
+	pattrib->rate = pmlmeext->tx_rate;
+
+	pattrib->encrypt = _NO_PRIVACY_;
+	pattrib->bswenc = _FALSE;
+
+	pattrib->qos_en = _FALSE;
+	pattrib->ht_en = _FALSE;
+	pattrib->bwmode = CHANNEL_WIDTH_20;
+	pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	pattrib->sgi = _FALSE;
+
+	pattrib->seqnum = pmlmeext->mgnt_seq;
+
+	pattrib->retry_ctrl = _TRUE;
+
+	pattrib->mbssid = 0;
+	pattrib->hw_ssn_sel = pxmitpriv->hw_ssn_seq_no;
+}
+
+void update_mgntframe_attrib_addr(_adapter *padapter, struct xmit_frame *pmgntframe)
+{
+	u8	*pframe;
+	struct pkt_attrib	*pattrib = &pmgntframe->attrib;
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+
+	_rtw_memcpy(pattrib->ra, GetAddr1Ptr(pframe), ETH_ALEN);
+	_rtw_memcpy(pattrib->ta, get_addr2_ptr(pframe), ETH_ALEN);
+
+}
+
+void dump_mgntframe(_adapter *padapter, struct xmit_frame *pmgntframe)
+{
+	if (RTW_CANNOT_RUN(padapter)) {
+		rtw_free_xmitbuf(&padapter->xmitpriv, pmgntframe->pxmitbuf);
+		rtw_free_xmitframe(&padapter->xmitpriv, pmgntframe);
+		return;
+	}
+
+	rtw_hal_mgnt_xmit(padapter, pmgntframe);
+}
+
+s32 dump_mgntframe_and_wait(_adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms)
+{
+	s32 ret = _FAIL;
+	_irqL irqL;
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+	struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf;
+	struct submit_ctx sctx;
+
+	if (RTW_CANNOT_RUN(padapter)) {
+		rtw_free_xmitbuf(&padapter->xmitpriv, pmgntframe->pxmitbuf);
+		rtw_free_xmitframe(&padapter->xmitpriv, pmgntframe);
+		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, __func__);
+
+	_enter_critical(&pxmitpriv->lock_sctx, &irqL);
+	pxmitbuf->sctx = NULL;
+	_exit_critical(&pxmitpriv->lock_sctx, &irqL);
+
+	return ret;
+}
+
+s32 dump_mgntframe_and_wait_ack_timeout(_adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms)
+{
+	static u8 seq_no = 0;
+	s32 ret = _FAIL;
+	struct xmit_priv	*pxmitpriv = &(GET_PRIMARY_ADAPTER(padapter))->xmitpriv;
+
+	if (RTW_CANNOT_RUN(padapter)) {
+		rtw_free_xmitbuf(&padapter->xmitpriv, pmgntframe->pxmitbuf);
+		rtw_free_xmitframe(&padapter->xmitpriv, pmgntframe);
+		return -1;
+	}
+
+	_enter_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL);
+	pxmitpriv->ack_tx = _TRUE;
+	pxmitpriv->seq_no = seq_no++;
+	pmgntframe->ack_report = 1;
+	rtw_sctx_init(&(pxmitpriv->ack_tx_ops), timeout_ms);
+	if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS)
+		ret = rtw_sctx_wait(&(pxmitpriv->ack_tx_ops), __func__);
+
+	pxmitpriv->ack_tx = _FALSE;
+	_exit_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL);
+
+	return ret;
+}
+
+s32 dump_mgntframe_and_wait_ack(_adapter *padapter, struct xmit_frame *pmgntframe)
+{
+	/* In this case, use 500 ms as the default wait_ack timeout */
+	return dump_mgntframe_and_wait_ack_timeout(padapter, pmgntframe, 500);
+}
+
+int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode)
+{
+	u8 *ssid_ie;
+	sint ssid_len_ori;
+	int len_diff = 0;
+
+	ssid_ie = rtw_get_ie(ies,  WLAN_EID_SSID, &ssid_len_ori, ies_len);
+
+	/* RTW_INFO("%s hidden_ssid_mode:%u, ssid_ie:%p, ssid_len_ori:%d\n", __FUNCTION__, hidden_ssid_mode, ssid_ie, ssid_len_ori); */
+
+	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;
+			_rtw_memcpy(ssid_ie + 2, next_ie, remain_len);
+			len_diff -= ssid_len_ori;
+
+			break;
+		}
+		case 2:
+			_rtw_memset(&ssid_ie[2], 0, ssid_len_ori);
+			break;
+		default:
+			break;
+		}
+	}
+
+	return len_diff;
+}
+
+void issue_beacon(_adapter *padapter, int timeout_ms)
+{
+	struct xmit_frame	*pmgntframe;
+	struct pkt_attrib	*pattrib;
+	unsigned char	*pframe;
+	struct rtw_ieee80211_hdr *pwlanhdr;
+	unsigned short *fctrl;
+	unsigned int	rate_len;
+	struct xmit_priv	*pxmitpriv = &(padapter->xmitpriv);
+	_irqL irqL;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX		*cur_network = &(pmlmeinfo->network);
+	u8	bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+
+	/* RTW_INFO("%s\n", __FUNCTION__); */
+
+	pmgntframe = rtw_alloc_bcnxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+	{
+		RTW_INFO("%s, alloc mgnt frame fail\n", __FUNCTION__);
+		return;
+	}
+	_enter_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+	pattrib->qsel = QSLT_BEACON;
+
+
+	_rtw_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;
+
+	_rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
+	/* pmlmeext->mgnt_seq++; */
+	set_frame_sub_type(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) {
+		/* RTW_INFO("ie len=%d\n", cur_network->IELength); */
+		/* 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;
+				_rtw_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: */
+				*(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE);
+				insert_len += 2;
+
+				/*	Length: */
+				*(u16 *)(pframe + insert_len) = cpu_to_be16(0x0008);
+				insert_len += 2;
+
+				/*	Value: */
+				/*	Category ID */
+				*(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+				insert_len += 2;
+
+				/*	OUI */
+				*(u32 *)(pframe + insert_len) = cpu_to_be32(WPSOUI);
+				insert_len += 4;
+
+				/*	Sub Category ID */
+				*(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+				insert_len += 2;
+
+				/*	Device Name */
+				/*	Type: */
+				*(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+				insert_len += 2;
+
+				/*	Length: */
+				*(u16 *)(pframe + insert_len) = cpu_to_be16(pwdinfo->device_name_len);
+				insert_len += 2;
+
+				/*	Value: */
+				_rtw_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 */
+				_rtw_memcpy(pframe, premainder_ie, remainder_ielen);
+				pframe += remainder_ielen;
+				pattrib->pktlen += remainder_ielen;
+			}
+		} else
+		{
+			int len_diff;
+			_rtw_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);
+		}
+
+		if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+			u32 len;
+			{
+				len = build_beacon_p2p_ie(pwdinfo, pframe);
+			}
+
+			pframe += len;
+			pattrib->pktlen += len;
+
+			len = rtw_append_beacon_wfd_ie(padapter, pframe);
+			pframe += len;
+			pattrib->pktlen += len;
+		}
+
+		goto _issue_bcn;
+
+	}
+
+	/* below for ad-hoc mode */
+
+	/* timestamp will be inserted by hardware */
+	pframe += 8;
+	pattrib->pktlen += 8;
+
+	/* beacon interval: 2 bytes */
+
+	_rtw_memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2);
+
+	pframe += 2;
+	pattrib->pktlen += 2;
+
+	/* capability info: 2 bytes */
+
+	_rtw_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);
+
+	/* 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 */
+
+_issue_bcn:
+
+	pmlmepriv->update_bcn = _FALSE;
+
+	_exit_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
+
+	if ((pattrib->pktlen + TXDESC_SIZE) > 512) {
+		RTW_INFO("beacon frame too large\n");
+		return;
+	}
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	/* RTW_INFO("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(_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;
+	unsigned short				*fctrl;
+	unsigned char					*mac, *bssid;
+	struct xmit_priv	*pxmitpriv = &(padapter->xmitpriv);
+	u8 *pwps_ie;
+	uint wps_ielen;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX		*cur_network = &(pmlmeinfo->network);
+	unsigned int	rate_len;
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	u32					wfdielen = 0;
+
+	/* RTW_INFO("%s\n", __FUNCTION__); */
+
+	if (da == NULL)
+		return;
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
+		return;
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL) {
+		RTW_INFO("%s, alloc mgnt frame fail\n", __FUNCTION__);
+		return;
+	}
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	mac = adapter_mac_addr(padapter);
+	bssid = cur_network->MacAddress;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+	_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, bssid, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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 ((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;
+
+			_rtw_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) {
+				_rtw_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) {
+				_rtw_memcpy(pframe, premainder_ie, remainder_ielen);
+				pframe += remainder_ielen;
+				pattrib->pktlen += remainder_ielen;
+			}
+		} else {
+			_rtw_memcpy(pframe, cur_network->IEs, cur_network->IELength);
+			pframe += cur_network->IELength;
+			pattrib->pktlen += cur_network->IELength;
+		}
+
+		/* retrieve SSID IE from cur_network->Ssid */
+		{
+			u8 *ssid_ie;
+			sint ssid_ielen;
+			sint ssid_ielen_diff;
+			u8 buf[MAX_IE_SZ];
+			u8 *ies = pmgntframe->buf_addr + TXDESC_OFFSET + sizeof(struct rtw_ieee80211_hdr_3addr);
+
+			ssid_ie = rtw_get_ie(ies + _FIXED_IE_LENGTH_, _SSID_IE_, &ssid_ielen,
+				     (pframe - ies) - _FIXED_IE_LENGTH_);
+
+			ssid_ielen_diff = cur_network->Ssid.SsidLength - ssid_ielen;
+
+			if (ssid_ie &&  cur_network->Ssid.SsidLength) {
+				uint remainder_ielen;
+				u8 *remainder_ie;
+				remainder_ie = ssid_ie + 2;
+				remainder_ielen = (pframe - remainder_ie);
+
+				if (remainder_ielen > MAX_IE_SZ) {
+					RTW_WARN(FUNC_ADPT_FMT" remainder_ielen > MAX_IE_SZ\n", FUNC_ADPT_ARG(padapter));
+					remainder_ielen = MAX_IE_SZ;
+				}
+
+				_rtw_memcpy(buf, remainder_ie, remainder_ielen);
+				_rtw_memcpy(remainder_ie + ssid_ielen_diff, buf, remainder_ielen);
+				*(ssid_ie + 1) = cur_network->Ssid.SsidLength;
+				_rtw_memcpy(ssid_ie + 2, cur_network->Ssid.Ssid, cur_network->Ssid.SsidLength);
+
+				pframe += ssid_ielen_diff;
+				pattrib->pktlen += ssid_ielen_diff;
+			}
+		}
+	} else
+	{
+
+		/* timestamp will be inserted by hardware */
+		pframe += 8;
+		pattrib->pktlen += 8;
+
+		/* beacon interval: 2 bytes */
+
+		_rtw_memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2);
+
+		pframe += 2;
+		pattrib->pktlen += 2;
+
+		/* capability info: 2 bytes */
+
+		_rtw_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 */
+
+	}
+
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)
+	    /* IOT issue, When wifi_spec is not set, send probe_resp with P2P IE even if probe_req has no P2P IE */
+	    && (is_valid_p2p_probereq || !padapter->registrypriv.wifi_spec)) {
+		u32 len;
+		{
+			len = build_probe_resp_p2p_ie(pwdinfo, pframe);
+		}
+
+		pframe += len;
+		pattrib->pktlen += len;
+
+		len = rtw_append_probe_resp_wfd_ie(padapter, pframe);
+		pframe += len;
+		pattrib->pktlen += len;
+	}
+
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+
+}
+
+int _issue_probereq(_adapter *padapter, NDIS_802_11_SSID *pssid, u8 *da, u8 ch, bool append_wps, int wait_ack)
+{
+	int ret = _FAIL;
+	struct xmit_frame		*pmgntframe;
+	struct pkt_attrib		*pattrib;
+	unsigned char			*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short		*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);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	int	bssrate_len = 0;
+	u8	bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
+		goto exit;
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		goto exit;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	mac = adapter_mac_addr(padapter);
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	if (da) {
+		/*	unicast probe request frame */
+		_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+		_rtw_memcpy(pwlanhdr->addr3, da, ETH_ALEN);
+	} else {
+		/*	broadcast probe request frame */
+		_rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+		_rtw_memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN);
+	}
+
+	_rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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));
+
+	if (ch)
+		pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, &ch, &pattrib->pktlen);
+
+	if (append_wps) {
+		/* add wps_ie for wps2.0 */
+		if (pmlmepriv->wps_probe_req_ie_len > 0 && pmlmepriv->wps_probe_req_ie) {
+			_rtw_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;
+			/* pmlmepriv->wps_probe_req_ie_len = 0 ; */ /* reset to zero */
+		}
+	}
+
+	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;
+}
+
+inline void issue_probereq(_adapter *padapter, NDIS_802_11_SSID *pssid, u8 *da)
+{
+	_issue_probereq(padapter, pssid, da, 0, 1, _FALSE);
+}
+
+/*
+ * wait_ms == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT
+ * wait_ms > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX
+ * try_cnt means the maximal TX count to try
+ */
+int issue_probereq_ex(_adapter *padapter, NDIS_802_11_SSID *pssid, u8 *da, u8 ch, bool append_wps,
+		      int try_cnt, int wait_ms)
+{
+	int ret = _FAIL;
+	int i = 0;
+	u32 start = rtw_get_current_time();
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
+		return _FAIL;
+
+	do {
+		ret = _issue_probereq(padapter, pssid, da, ch, append_wps, wait_ms > 0 ? _TRUE : _FALSE);
+
+		i++;
+
+		if (RTW_CANNOT_RUN(padapter))
+			break;
+
+		if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+			rtw_msleep_os(wait_ms);
+
+	} while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+	return ret == _FAIL ? _FAIL : _SUCCESS;
+}
+
+/* if psta == NULL, indiate we are station(client) now... */
+void issue_auth(_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;
+	unsigned short				*fctrl;
+	unsigned int					val32;
+	unsigned short				val16;
+	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);
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
+		return;
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_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++;
+	set_frame_sub_type(pframe, WIFI_AUTH);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	if (psta) { /* for AP mode */
+
+		_rtw_memcpy(pwlanhdr->addr1, psta->hwaddr, ETH_ALEN);
+		_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+		_rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN);
+
+		/* setting auth algo number */
+		val16 = (u16)psta->authalg;
+
+		if (status != _STATS_SUCCESSFUL_)
+			val16 = 0;
+
+		if (val16)	{
+			val16 = cpu_to_le16(val16);
+			use_shared_key = 1;
+		}
+
+		pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&val16, &(pattrib->pktlen));
+
+		/* setting auth seq number */
+		val16 = (u16)psta->auth_seq;
+		val16 = cpu_to_le16(val16);
+		pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&val16, &(pattrib->pktlen));
+
+		/* setting status code... */
+		val16 = status;
+		val16 = cpu_to_le16(val16);
+		pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&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));
+	} else {
+		_rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
+		_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+		_rtw_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) {
+				val16 = cpu_to_le16(val16);
+				use_shared_key = 1;
+			}
+		}
+
+		/* RTW_INFO("%s auth_algo= %s auth_seq=%d\n",__FUNCTION__,(pmlmeinfo->auth_algo==0)?"OPEN":"SHARED",pmlmeinfo->auth_seq); */
+
+		/* setting IV for auth seq #3 */
+		if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) {
+			/* RTW_INFO("==> iv(%d),key_index(%d)\n",pmlmeinfo->iv,pmlmeinfo->key_index); */
+			val32 = ((pmlmeinfo->iv++) | (pmlmeinfo->key_index << 30));
+			val32 = cpu_to_le32(val32);
+			pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&val32, &(pattrib->pktlen));
+
+			pattrib->iv_len = 4;
+		}
+
+		pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&val16, &(pattrib->pktlen));
+
+		/* setting auth seq number */
+		val16 = pmlmeinfo->auth_seq;
+		val16 = cpu_to_le16(val16);
+		pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&val16, &(pattrib->pktlen));
+
+		/* setting status code... */
+		val16 = status;
+		val16 = cpu_to_le16(val16);
+		pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&val16, &(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);
+	RTW_INFO("%s\n", __FUNCTION__);
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+}
+
+void issue_asocrsp(_adapter *padapter, unsigned short status, struct sta_info *pstat, int pkt_type)
+{
+	struct xmit_frame	*pmgntframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	struct pkt_attrib *pattrib;
+	unsigned char	*pbuf, *pframe;
+	unsigned short val, ie_status;
+	unsigned short *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);
+	WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network);
+	u8 *ie = pnetwork->IEs;
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	u32					wfdielen = 0;
+
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
+		return;
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_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;
+
+	_rtw_memcpy((void *)GetAddr1Ptr(pwlanhdr), pstat->hwaddr, ETH_ALEN);
+	_rtw_memcpy((void *)get_addr2_ptr(pwlanhdr), adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_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))
+		set_frame_sub_type(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));
+
+	ie_status = cpu_to_le16(status);
+	pframe = rtw_set_fixed_ie(pframe , _STATUS_CODE_ , (unsigned char *)&ie_status, &(pattrib->pktlen));
+
+	val = cpu_to_le16(pstat->aid | BIT(14) | BIT(15));
+	pframe = rtw_set_fixed_ie(pframe, _ASOC_ID_ , (unsigned char *)&val, &(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 */
+		/* p = hostapd_eid_ht_capabilities_info(hapd, p); */
+		pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+		if (pbuf && ie_len > 0) {
+			_rtw_memcpy(pframe, pbuf, ie_len + 2);
+			pframe += (ie_len + 2);
+			pattrib->pktlen += (ie_len + 2);
+		}
+
+		/* FILL HT ADD INFO IE */
+		/* p = hostapd_eid_ht_operation(hapd, p); */
+		pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+		if (pbuf && ie_len > 0) {
+			_rtw_memcpy(pframe, pbuf, ie_len + 2);
+			pframe += (ie_len + 2);
+			pattrib->pktlen += (ie_len + 2);
+		}
+
+	}
+
+	/*adding EXT_CAPAB_IE */
+	if (pmlmepriv->ext_capab_ie_len > 0) {
+		uint ie_len = 0;
+
+		pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_CAP_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+		if (pbuf && ie_len > 0) {
+			_rtw_memcpy(pframe, pbuf, ie_len + 2);
+			pframe += (ie_len + 2);
+			pattrib->pktlen += (ie_len + 2);
+		}
+	}
+
+	if ((pstat->flags & WLAN_STA_VHT) && (pmlmepriv->vhtpriv.vht_option)
+	    && (pstat->wpa_pairwise_cipher != WPA_CIPHER_TKIP)
+	    && (pstat->wpa2_pairwise_cipher != WPA_CIPHER_TKIP)) {
+		u32 ie_len = 0;
+
+		/* FILL VHT CAP IE */
+		pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, EID_VHTCapability, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+		if (pbuf && ie_len > 0) {
+			_rtw_memcpy(pframe, pbuf, ie_len + 2);
+			pframe += (ie_len + 2);
+			pattrib->pktlen += (ie_len + 2);
+		}
+
+		/* FILL VHT OPERATION IE */
+		pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, EID_VHTOperation, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+		if (pbuf && ie_len > 0) {
+			_rtw_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 && _rtw_memcmp(pbuf + 2, WMM_PARA_IE, 6)) {
+				_rtw_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) {
+		_rtw_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;
+	}
+
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && (pstat->is_p2p_device == _TRUE)) {
+		u32 len;
+
+		if (padapter->wdinfo.driver_interface == DRIVER_CFG80211) {
+			len = 0;
+			if (pmlmepriv->p2p_assoc_resp_ie && pmlmepriv->p2p_assoc_resp_ie_len > 0) {
+				len = pmlmepriv->p2p_assoc_resp_ie_len;
+				_rtw_memcpy(pframe, pmlmepriv->p2p_assoc_resp_ie, len);
+			}
+		} else
+			len = build_assoc_resp_p2p_ie(pwdinfo, pframe, pstat->p2p_status_code);
+		pframe += len;
+		pattrib->pktlen += len;
+	}
+
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+		wfdielen = rtw_append_assoc_resp_wfd_ie(padapter, pframe);
+		pframe += wfdielen;
+		pattrib->pktlen += wfdielen;
+	}
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+
+}
+
+void _issue_assocreq(_adapter *padapter, u8 is_reassoc)
+{
+	int ret = _FAIL;
+	struct xmit_frame				*pmgntframe;
+	struct pkt_attrib				*pattrib;
+	unsigned char					*pframe, *p;
+	struct rtw_ieee80211_hdr			*pwlanhdr;
+	unsigned short				*fctrl;
+	unsigned short				val16;
+	unsigned int					i, j, ie_len, index = 0;
+	unsigned char					rf_type, bssrate[NumRates], sta_bssrate[NumRates];
+	PNDIS_802_11_VARIABLE_IEs	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;
+	u8	vs_ie_length = 0;
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	u8					p2pie[255] = { 0x00 };
+	u16					p2pielen = 0;
+	u32					wfdielen = 0;
+
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
+		goto exit;
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		goto exit;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_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;
+	_rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	if (is_reassoc == _TRUE)
+		set_frame_sub_type(pframe, WIFI_REASSOCREQ);
+	else
+		set_frame_sub_type(pframe, WIFI_ASSOCREQ);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	/* caps */
+
+	_rtw_memcpy(pframe, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2);
+
+	pframe += 2;
+	pattrib->pktlen += 2;
+
+	/* listen interval */
+	/* todo: listen interval for power saving */
+	val16 = cpu_to_le16(3);
+	_rtw_memcpy(pframe , (unsigned char *)&val16, 2);
+	pframe += 2;
+	pattrib->pktlen += 2;
+
+	/*Construct Current AP Field for Reassoc-Req only*/
+	if (is_reassoc == _TRUE) {
+		_rtw_memcpy(pframe, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+		pframe += ETH_ALEN;
+		pattrib->pktlen += ETH_ALEN;
+	}
+
+	/* SSID */
+	pframe = rtw_set_ie(pframe, _SSID_IE_,  pmlmeinfo->network.Ssid.SsidLength, pmlmeinfo->network.Ssid.Ssid, &(pattrib->pktlen));
+
+
+	/* supported rate & extended supported rate */
+
+	get_rate_set(padapter, sta_bssrate, &sta_bssrate_len);
+	/* RTW_INFO("sta_bssrate_len=%d\n", 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 < sta_bssrate_len; i++) { */
+	/*	RTW_INFO("sta_bssrate[%d]=%02X\n", i, sta_bssrate[i]); */
+	/* } */
+
+	for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
+		if (pmlmeinfo->network.SupportedRates[i] == 0)
+			break;
+		RTW_INFO("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)) {
+				/* RTW_INFO("match i = %d, j=%d\n", i, j); */
+				break;
+			} else {
+				/* RTW_INFO("not match: %02X != %02X\n", (pmlmeinfo->network.SupportedRates[i]|IEEE80211_BASIC_RATE_MASK), (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK)); */
+			}
+		}
+
+		if (j == sta_bssrate_len) {
+			/* the rate is not supported by STA */
+			RTW_INFO("%s(): the rate[%d]=%02X is not supported by STA!\n", __FUNCTION__, i, pmlmeinfo->network.SupportedRates[i]);
+		} else {
+			/* the rate is supported by STA */
+			bssrate[index++] = pmlmeinfo->network.SupportedRates[i];
+		}
+	}
+
+	bssrate_len = index;
+	RTW_INFO("bssrate_len = %d\n", bssrate_len);
+
+	if ((bssrate_len == 0) && (pmlmeinfo->network.SupportedRates[0] != 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 if (bssrate_len > 0)
+		pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen));
+	else
+		RTW_INFO("%s: Connect to AP without 11b and 11g data rate!\n", __FUNCTION__);
+
+	/* vendor specific IE, such as WPA, WMM, WPS */
+	for (i = sizeof(NDIS_802_11_FIXED_IEs); i < pmlmeinfo->network.IELength;) {
+		pIE = (PNDIS_802_11_VARIABLE_IEs)(pmlmeinfo->network.IEs + i);
+
+		switch (pIE->ElementID) {
+		case _VENDOR_SPECIFIC_IE_:
+			if ((_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4)) ||
+			    (_rtw_memcmp(pIE->data, WMM_OUI, 4)) ||
+			    (_rtw_memcmp(pIE->data, WPS_OUI, 4))) {
+				vs_ie_length = pIE->Length;
+				if ((!padapter->registrypriv.wifi_spec) && (_rtw_memcmp(pIE->data, WPS_OUI, 4))) {
+					/* Commented by Kurt 20110629 */
+					/* In some older APs, WPS handshake */
+					/* would be fail if we append vender extensions informations to AP */
+
+					vs_ie_length = 14;
+				}
+
+				pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, vs_ie_length, pIE->data, &(pattrib->pktlen));
+			}
+			break;
+
+		case EID_WPA2:
+				pframe = rtw_set_ie(pframe, EID_WPA2, pIE->Length, pIE->data, &(pattrib->pktlen));
+			break;
+		case EID_HTCapability:
+			if (padapter->mlmepriv.htpriv.ht_option == _TRUE) {
+				if (!(is_ap_in_tkip(padapter))) {
+					_rtw_memcpy(&(pmlmeinfo->HT_caps), pIE->data, sizeof(struct HT_caps_element));
+
+					pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info = cpu_to_le16(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info);
+
+					pframe = rtw_set_ie(pframe, EID_HTCapability, pIE->Length , (u8 *)(&(pmlmeinfo->HT_caps)), &(pattrib->pktlen));
+				}
+			}
+			break;
+
+		case EID_EXTCapability:
+			if (padapter->mlmepriv.htpriv.ht_option == _TRUE)
+				pframe = rtw_set_ie(pframe, EID_EXTCapability, pIE->Length, pIE->data, &(pattrib->pktlen));
+			break;
+		case EID_VHTCapability:
+			if (padapter->mlmepriv.vhtpriv.vht_option == _TRUE)
+				pframe = rtw_set_ie(pframe, EID_VHTCapability, pIE->Length, pIE->data, &(pattrib->pktlen));
+			break;
+
+		case EID_OpModeNotification:
+			if (padapter->mlmepriv.vhtpriv.vht_option == _TRUE)
+				pframe = rtw_set_ie(pframe, EID_OpModeNotification, 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));
+
+
+	{
+		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: */
+			*(u16 *)(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: */
+			*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004);
+			p2pielen += 2;
+
+			/*	Value: */
+			/*	Availability Period */
+			*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+			p2pielen += 2;
+
+			/*	Availability Interval */
+			*(u16 *)(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) */
+			*(u16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len);
+			p2pielen += 2;
+
+			/*	Value: */
+			/*	P2P Device Address */
+			_rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), 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))
+				*(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY);
+			else
+				*(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_PBC);
+
+			p2pielen += 2;
+
+			/*	Primary Device Type */
+			/*	Category ID */
+			*(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+			p2pielen += 2;
+
+			/*	OUI */
+			*(u32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI);
+			p2pielen += 4;
+
+			/*	Sub Category ID */
+			*(u16 *)(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: */
+			*(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+			p2pielen += 2;
+
+			/*	Length: */
+			*(u16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len);
+			p2pielen += 2;
+
+			/*	Value: */
+			_rtw_memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len);
+			p2pielen += pwdinfo->device_name_len;
+
+			/*	P2P Interface */
+			/*	Type: */
+			p2pie[p2pielen++] = P2P_ATTR_INTERFACE;
+
+			/*	Length: */
+			*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x000D);
+			p2pielen += 2;
+
+			/*	Value: */
+			_rtw_memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN);	/*	P2P Device Address */
+			p2pielen += ETH_ALEN;
+
+			p2pie[p2pielen++] = 1;	/*	P2P Interface Address Count */
+
+			_rtw_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);
+		}
+	}
+
+
+	wfdielen = rtw_append_assoc_req_wfd_ie(padapter, pframe);
+	pframe += wfdielen;
+	pattrib->pktlen += wfdielen;
+
+	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;
+}
+
+void issue_assocreq(_adapter *padapter)
+{
+	_issue_assocreq(padapter, _FALSE);
+}
+
+void issue_reassocreq(_adapter *padapter)
+{
+	_issue_assocreq(padapter, _TRUE);
+}
+
+/* when wait_ack is ture, this function shoule be called at process context */
+static int _issue_nulldata(_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;
+	unsigned short				*fctrl;
+	struct xmit_priv	*pxmitpriv;
+	struct mlme_ext_priv	*pmlmeext;
+	struct mlme_ext_info	*pmlmeinfo;
+
+	/* RTW_INFO("%s:%d\n", __FUNCTION__, power_mode); */
+
+	if (!padapter)
+		goto exit;
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(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;
+
+	_rtw_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);
+
+	_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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;
+}
+
+/*
+ * [IMPORTANT] Don't call this function in interrupt context
+ *
+ * When wait_ms > 0, this function should be called at process context
+ * wait_ms == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT
+ * wait_ms > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX
+ * try_cnt means the maximal TX count to try
+ * da == NULL for station mode
+ */
+int issue_nulldata(_adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms)
+{
+	int ret = _FAIL;
+	int i = 0;
+	u32 start = rtw_get_current_time();
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct sta_info *psta;
+	u8 macid_sleep_reg_access = _TRUE;
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
+		return _FAIL;
+
+	/* da == NULL, assum it's null data for sta to ap*/
+	if (da == NULL)
+		da = get_my_bssid(&(pmlmeinfo->network));
+
+	psta = rtw_get_stainfo(&padapter->stapriv, da);
+	if (psta) {
+		if (macid_sleep_reg_access) {
+			if (power_mode)
+				rtw_hal_macid_sleep(padapter, psta->mac_id);
+			else
+				rtw_hal_macid_wakeup(padapter, psta->mac_id);
+		}
+	} else {
+		RTW_INFO(FUNC_ADPT_FMT ": Can't find sta info for " MAC_FMT ", skip macid %s!!\n",
+			FUNC_ADPT_ARG(padapter), MAC_ARG(da), power_mode ? "sleep" : "wakeup");
+		rtw_warn_on(1);
+	}
+
+	do {
+		ret = _issue_nulldata(padapter, da, power_mode, wait_ms > 0 ? _TRUE : _FALSE);
+
+		i++;
+
+		if (RTW_CANNOT_RUN(padapter))
+			break;
+
+		if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+			rtw_msleep_os(wait_ms);
+
+	} while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+	return ret == _FAIL ? _FAIL : _SUCCESS;
+}
+
+/*
+ * [IMPORTANT] This function run in interrupt context
+ *
+ * The null data packet would be sent without power bit,
+ * and not guarantee success.
+ */
+s32 issue_nulldata_in_interrupt(PADAPTER padapter, u8 *da, unsigned int power_mode)
+{
+	int ret;
+	struct mlme_ext_priv *pmlmeext;
+	struct mlme_ext_info *pmlmeinfo;
+
+	pmlmeext = &padapter->mlmeextpriv;
+	pmlmeinfo = &pmlmeext->mlmext_info;
+
+	/* da == NULL, assum it's null data for sta to ap*/
+	if (da == NULL)
+		da = get_my_bssid(&(pmlmeinfo->network));
+
+	ret = _issue_nulldata(padapter, da, power_mode, _FALSE);
+
+	return ret;
+}
+
+/* when wait_ack is ture, this function shoule be called at process context */
+static int _issue_qos_nulldata(_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;
+	unsigned short				*fctrl, *qc;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
+		goto exit;
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	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;
+
+	_rtw_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);
+
+	_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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 should be called at process context
+ * wait_ms == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT
+ * wait_ms > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX
+ * try_cnt means the maximal TX count to try
+ * da == NULL for station mode
+ */
+int issue_qos_nulldata(_adapter *padapter, unsigned char *da, u16 tid, int try_cnt, int wait_ms)
+{
+	int ret = _FAIL;
+	int i = 0;
+	u32 start = rtw_get_current_time();
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
+		return _FAIL;
+
+	/* 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 (RTW_CANNOT_RUN(padapter))
+			break;
+
+		if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+			rtw_msleep_os(wait_ms);
+
+	} while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+	return ret == _FAIL ? _FAIL : _SUCCESS;
+}
+
+static int _issue_deauth(_adapter *padapter, unsigned char *da, unsigned short reason, u8 wait_ack, u8 key_type)
+{
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*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;
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	/* RTW_INFO("%s to "MAC_FMT"\n", __func__, MAC_ARG(da)); */
+
+	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);
+	}
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
+		goto exit;
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		goto exit;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+	pattrib->retry_ctrl = _FALSE;
+	pattrib->key_type = key_type;
+	_rtw_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;
+
+	_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(pframe, WIFI_DEAUTH);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	reason = cpu_to_le16(reason);
+	pframe = rtw_set_fixed_ie(pframe, _RSON_CODE_ , (unsigned char *)&reason, &(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(_adapter *padapter, unsigned char *da, unsigned short reason)
+{
+	RTW_INFO("%s to "MAC_FMT"\n", __func__, MAC_ARG(da));
+	return _issue_deauth(padapter, da, reason, _FALSE, IEEE80211W_RIGHT_KEY);
+}
+
+
+/*
+ * wait_ms == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT
+ * wait_ms > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX
+ * try_cnt means the maximal TX count to try
+ */
+int issue_deauth_ex(_adapter *padapter, u8 *da, unsigned short reason, int try_cnt,
+		    int wait_ms)
+{
+	int ret = _FAIL;
+	int i = 0;
+	u32 start = rtw_get_current_time();
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
+		return _FAIL;
+
+	do {
+		ret = _issue_deauth(padapter, da, reason, wait_ms > 0 ? _TRUE : _FALSE, IEEE80211W_RIGHT_KEY);
+
+		i++;
+
+		if (RTW_CANNOT_RUN(padapter))
+			break;
+
+		if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+			rtw_msleep_os(wait_ms);
+
+	} while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+	return ret == _FAIL ? _FAIL : _SUCCESS;
+}
+
+void issue_action_spct_ch_switch(_adapter *padapter, u8 *ra, u8 new_ch, u8 ch_offset)
+{
+	_irqL	irqL;
+	_list		*plist, *phead;
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char				*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short			*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);
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
+		return;
+
+	RTW_INFO(FUNC_NDEV_FMT" ra="MAC_FMT", ch:%u, offset:%u\n",
+		FUNC_NDEV_ARG(padapter->pnetdev), MAC_ARG(ra), new_ch, ch_offset);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_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;
+
+	_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); /* RA */
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); /* TA */
+	_rtw_memcpy(pwlanhdr->addr3, ra, ETH_ALEN); /* DA = RA */
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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);
+
+}
+
+
+/**
+ * issue_action_ba - internal function to TX Block Ack action frame
+ * @padapter: the adapter to TX
+ * @raddr: receiver address
+ * @action: Block Ack Action
+ * @tid: tid
+ * @size: the announced AMPDU buffer size. used by ADDBA_RESP
+ * @status: status/reason code. used by ADDBA_RESP, DELBA
+ * @initiator: if we are the initiator of AMPDU association. used by DELBA
+ * @wait_ack: used xmit ack
+ *
+ * Returns:
+ * _SUCCESS: No xmit ack is used or acked
+ * _FAIL: not acked when using xmit ack
+ */
+static int issue_action_ba(_adapter *padapter, unsigned char *raddr, unsigned char action
+		   , u8 tid, u8 size, u16 status, u8 initiator, int wait_ack)
+{
+	int ret = _FAIL;
+	u8	category = RTW_WLAN_CATEGORY_BACK;
+	u16	start_seq;
+	u16	BA_para_set;
+	u16	BA_timeout_value;
+	u16	BA_starting_seqctrl;
+	struct xmit_frame		*pmgntframe;
+	struct pkt_attrib		*pattrib;
+	u8					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	u16					*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;
+
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
+		goto exit;
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		goto exit;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_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;
+
+	/* _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); */
+	_rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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 RTW_WLAN_ACTION_ADDBA_REQ:
+			do {
+				pmlmeinfo->dialogToken++;
+			} while (pmlmeinfo->dialogToken == 0);
+			pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->dialogToken), &(pattrib->pktlen));
+
+			BA_para_set = (0x1002 | ((tid & 0xf) << 2)); /* immediate ack & 64 buffer size */
+
+			BA_para_set = cpu_to_le16(BA_para_set);
+			pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_para_set)), &(pattrib->pktlen));
+
+			/* BA_timeout_value = 0xffff; */ /* max: 65535 TUs(~ 65 ms) */
+			BA_timeout_value = 5000;/* ~ 5ms */
+			BA_timeout_value = cpu_to_le16(BA_timeout_value);
+			pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_timeout_value)), &(pattrib->pktlen));
+
+			/* if ((psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress)) != NULL) */
+			psta = rtw_get_stainfo(pstapriv, raddr);
+			if (psta != NULL) {
+				start_seq = (psta->sta_xmitpriv.txseq_tid[tid & 0x07] & 0xfff) + 1;
+
+				RTW_INFO("BA_starting_seqctrl = %d for TID=%d\n", start_seq, tid & 0x07);
+
+				psta->BA_starting_seqctrl[tid & 0x07] = start_seq;
+
+				BA_starting_seqctrl = start_seq << 4;
+			}
+
+			BA_starting_seqctrl = cpu_to_le16(BA_starting_seqctrl);
+			pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_starting_seqctrl)), &(pattrib->pktlen));
+			break;
+
+		case RTW_WLAN_ACTION_ADDBA_RESP:
+			pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->ADDBA_req.dialog_token), &(pattrib->pktlen));
+			status = cpu_to_le16(status);
+			pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&status), &(pattrib->pktlen));
+
+			BA_para_set = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set);
+
+			BA_para_set &= ~IEEE80211_ADDBA_PARAM_TID_MASK;
+			BA_para_set |= (tid << 2) & IEEE80211_ADDBA_PARAM_TID_MASK;
+
+			BA_para_set &= ~RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
+			BA_para_set |= (size << 6) & RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
+
+			if (!padapter->registrypriv.wifi_spec) {
+				if (pregpriv->rx_ampdu_amsdu == 0) /* disabled */
+					BA_para_set &= ~BIT(0);
+				else if (pregpriv->rx_ampdu_amsdu == 1) /* enabled */
+					BA_para_set |= BIT(0);
+			}
+
+			BA_para_set = cpu_to_le16(BA_para_set);
+
+			pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_para_set)), &(pattrib->pktlen));
+			pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(pmlmeinfo->ADDBA_req.BA_timeout_value)), &(pattrib->pktlen));
+			break;
+
+		case RTW_WLAN_ACTION_DELBA:
+			BA_para_set = 0;
+			BA_para_set |= (tid << 12) & IEEE80211_DELBA_PARAM_TID_MASK;
+			BA_para_set |= (initiator << 11) & IEEE80211_DELBA_PARAM_INITIATOR_MASK;
+
+			BA_para_set = cpu_to_le16(BA_para_set);
+			pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_para_set)), &(pattrib->pktlen));
+			status = cpu_to_le16(status);
+			pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(status)), &(pattrib->pktlen));
+			break;
+		default:
+			break;
+		}
+	}
+
+	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;
+}
+
+/**
+ * issue_addba_req - TX ADDBA_REQ
+ * @adapter: the adapter to TX
+ * @ra: receiver address
+ * @tid: tid
+ */
+inline void issue_addba_req(_adapter *adapter, unsigned char *ra, u8 tid)
+{
+	issue_action_ba(adapter, ra, RTW_WLAN_ACTION_ADDBA_REQ
+			, tid
+			, 0 /* unused */
+			, 0 /* unused */
+			, 0 /* unused */
+			, _FALSE
+		       );
+	RTW_INFO(FUNC_ADPT_FMT" ra="MAC_FMT" tid=%u\n"
+		 , FUNC_ADPT_ARG(adapter), MAC_ARG(ra), tid);
+
+}
+
+/**
+ * issue_addba_rsp - TX ADDBA_RESP
+ * @adapter: the adapter to TX
+ * @ra: receiver address
+ * @tid: tid
+ * @status: status code
+ * @size: the announced AMPDU buffer size
+ */
+inline void issue_addba_rsp(_adapter *adapter, unsigned char *ra, u8 tid, u16 status, u8 size)
+{
+	issue_action_ba(adapter, ra, RTW_WLAN_ACTION_ADDBA_RESP
+			, tid
+			, size
+			, status
+			, 0 /* unused */
+			, _FALSE
+		       );
+	RTW_INFO(FUNC_ADPT_FMT" ra="MAC_FMT" status=%u, tid=%u, size=%u\n"
+		 , FUNC_ADPT_ARG(adapter), MAC_ARG(ra), status, tid, size);
+}
+
+/**
+ * issue_addba_rsp_wait_ack - TX ADDBA_RESP and wait ack
+ * @adapter: the adapter to TX
+ * @ra: receiver address
+ * @tid: tid
+ * @status: status code
+ * @size: the announced AMPDU buffer size
+ * @try_cnt: the maximal TX count to try
+ * @wait_ms: == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT
+ *           > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX
+ */
+inline u8 issue_addba_rsp_wait_ack(_adapter *adapter, unsigned char *ra, u8 tid, u16 status, u8 size, int try_cnt, int wait_ms)
+{
+	int ret = _FAIL;
+	int i = 0;
+	u32 start = rtw_get_current_time();
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(adapter)))
+		return _FAIL;
+
+	do {
+		ret = issue_action_ba(adapter, ra, RTW_WLAN_ACTION_ADDBA_RESP
+				      , tid
+				      , size
+				      , status
+				      , 0 /* unused */
+				      , _TRUE
+				     );
+
+		i++;
+
+		if (RTW_CANNOT_RUN(adapter))
+			break;
+
+		if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+			rtw_msleep_os(wait_ms);
+
+	} while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+	return ret == _FAIL ? _FAIL : _SUCCESS;
+}
+
+/**
+ * issue_del_ba - TX DELBA
+ * @adapter: the adapter to TX
+ * @ra: receiver address
+ * @tid: tid
+ * @reason: reason code
+ * @initiator: if we are the initiator of AMPDU association. used by DELBA
+ */
+inline void issue_del_ba(_adapter *adapter, unsigned char *ra, u8 tid, u16 reason, u8 initiator)
+{
+	issue_action_ba(adapter, ra, RTW_WLAN_ACTION_DELBA
+			, tid
+			, 0 /* unused */
+			, reason
+			, initiator
+			, _FALSE
+		       );
+	RTW_INFO(FUNC_ADPT_FMT" ra="MAC_FMT" reason=%u, tid=%u, initiator=%u\n"
+		 , FUNC_ADPT_ARG(adapter), MAC_ARG(ra), reason, tid, initiator);
+}
+
+/**
+ * issue_del_ba_ex - TX DELBA with xmit ack options
+ * @adapter: the adapter to TX
+ * @ra: receiver address
+ * @tid: tid
+ * @reason: reason code
+ * @initiator: if we are the initiator of AMPDU association. used by DELBA
+ * @try_cnt: the maximal TX count to try
+ * @wait_ms: == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT
+ *           > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX
+ */
+int issue_del_ba_ex(_adapter *adapter, unsigned char *ra, u8 tid, u16 reason, u8 initiator
+		    , int try_cnt, int wait_ms)
+{
+	int ret = _FAIL;
+	int i = 0;
+	u32 start = rtw_get_current_time();
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(adapter)))
+		return _FAIL;
+
+	do {
+		ret = issue_action_ba(adapter, ra, RTW_WLAN_ACTION_DELBA
+				      , tid
+				      , 0 /* unused */
+				      , reason
+				      , initiator
+				      , wait_ms > 0 ? _TRUE : _FALSE
+				     );
+
+		i++;
+
+		if (RTW_CANNOT_RUN(adapter))
+			break;
+
+		if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+			rtw_msleep_os(wait_ms);
+
+	} while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+	return ret == _FAIL ? _FAIL : _SUCCESS;
+}
+
+static void issue_action_BSSCoexistPacket(_adapter *padapter)
+{
+	_irqL	irqL;
+	_list		*plist, *phead;
+	unsigned char category, action;
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char				*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short			*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);
+	_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 (_TRUE == pmlmeinfo->bwmode_updated)
+		return;
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
+		return;
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	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);
+
+	_rtw_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;
+
+	_rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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));
+
+	}
+
+	/*  */
+	_rtw_memset(ICS, 0, sizeof(ICS));
+	if (pmlmepriv->num_sta_no_ht > 0) {
+		int i;
+
+		_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+		phead = get_list_head(queue);
+		plist = get_next(phead);
+
+		while (1) {
+			int len;
+			u8 *p;
+			WLAN_BSSID_EX *pbss_network;
+
+			if (rtw_end_of_queue_search(phead, plist) == _TRUE)
+				break;
+
+			pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+			plist = get_next(plist);
+
+			pbss_network = (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;
+			}
+
+		}
+
+		_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+		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);
+}
+
+/* Spatial Multiplexing Powersave (SMPS) action frame */
+int _issue_action_SM_PS(_adapter *padapter ,  unsigned char *raddr , u8 NewMimoPsMode ,  u8 wait_ack)
+{
+
+	int ret = _FAIL;
+	unsigned char category = RTW_WLAN_CATEGORY_HT;
+	u8 action = RTW_WLAN_ACTION_HT_SM_PS;
+	u8 sm_power_control = 0;
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if (NewMimoPsMode == WLAN_HT_CAP_SM_PS_DISABLED) {
+		sm_power_control = sm_power_control  & ~(BIT(0)); /* SM Power Save Enable = 0 SM Power Save Disable */
+	} else if (NewMimoPsMode == WLAN_HT_CAP_SM_PS_STATIC) {
+		sm_power_control = sm_power_control | BIT(0);    /* SM Power Save Enable = 1 SM Power Save Enable  */
+		sm_power_control = sm_power_control & ~(BIT(1)); /* SM Mode = 0 Static Mode */
+	} else if (NewMimoPsMode == WLAN_HT_CAP_SM_PS_DYNAMIC) {
+		sm_power_control = sm_power_control | BIT(0); /* SM Power Save Enable = 1 SM Power Save Enable  */
+		sm_power_control = sm_power_control | BIT(1); /* SM Mode = 1 Dynamic Mode */
+	} else
+		return ret;
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
+		return ret;
+
+	RTW_INFO("%s, sm_power_control=%u, NewMimoPsMode=%u\n", __FUNCTION__ , sm_power_control , NewMimoPsMode);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return ret;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_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;
+
+	_rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); /* RA */
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); /* TA */
+	_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); /* DA = RA */
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(pframe, WIFI_ACTION);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	/* category, action */
+	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, 1, &(sm_power_control), &(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;
+	}
+
+	if (ret != _SUCCESS)
+		RTW_INFO("%s, ack to\n", __func__);
+
+	return ret;
+}
+
+/*
+ * wait_ms == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT
+ * wait_ms > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX
+ * try_cnt means the maximal TX count to try
+ */
+int issue_action_SM_PS_wait_ack(_adapter *padapter, unsigned char *raddr, u8 NewMimoPsMode, int try_cnt, int wait_ms)
+{
+	int ret = _FAIL;
+	int i = 0;
+	u32 start = rtw_get_current_time();
+
+	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
+		return _FAIL;
+
+	do {
+		ret = _issue_action_SM_PS(padapter, raddr, NewMimoPsMode , wait_ms > 0 ? _TRUE : _FALSE);
+
+		i++;
+
+		if (RTW_CANNOT_RUN(padapter))
+			break;
+
+		if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+			rtw_msleep_os(wait_ms);
+
+	} while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+	return ret == _FAIL ? _FAIL : _SUCCESS;
+}
+
+int issue_action_SM_PS(_adapter *padapter ,  unsigned char *raddr , u8 NewMimoPsMode)
+{
+	RTW_INFO("%s to "MAC_FMT"\n", __func__, MAC_ARG(raddr));
+	return _issue_action_SM_PS(padapter, raddr, NewMimoPsMode , _FALSE);
+}
+
+/**
+ * _send_delba_sta_tid - Cancel the AMPDU association for the specific @sta, @tid
+ * @adapter: the adapter to which @sta belongs
+ * @initiator: if we are the initiator of AMPDU association
+ * @sta: the sta to be checked
+ * @tid: the tid to be checked
+ * @force: cancel and send DELBA even when no AMPDU association is setup
+ * @wait_ack: send delba with xmit ack (valid when initiator == 0)
+ *
+ * Returns:
+ * _FAIL if sta is NULL
+ * when initiator is 1, always _SUCCESS
+ * when initiator is 0, _SUCCESS if DELBA is acked
+ */
+static unsigned int _send_delba_sta_tid(_adapter *adapter, u8 initiator, struct sta_info *sta, u8 tid
+					, u8 force, int wait_ack)
+{
+	int ret = _SUCCESS;
+
+	if (sta == NULL) {
+		ret = _FAIL;
+		goto exit;
+	}
+
+	if (initiator == 0) {
+		/* recipient */
+		if (force || sta->recvreorder_ctrl[tid].enable == _TRUE) {
+			u8 ampdu_size_bak = sta->recvreorder_ctrl[tid].ampdu_size;
+
+			sta->recvreorder_ctrl[tid].enable = _FALSE;
+			sta->recvreorder_ctrl[tid].ampdu_size = RX_AMPDU_SIZE_INVALID;
+
+			if (rtw_del_rx_ampdu_test_trigger_no_tx_fail())
+				ret = _FAIL;
+			else if (wait_ack)
+				ret = issue_del_ba_ex(adapter, sta->hwaddr, tid, 37, initiator, 3, 1);
+			else
+				issue_del_ba(adapter, sta->hwaddr, tid, 37, initiator);
+
+			if (ret == _FAIL && sta->recvreorder_ctrl[tid].enable == _FALSE)
+				sta->recvreorder_ctrl[tid].ampdu_size = ampdu_size_bak;
+		}
+	} else if (initiator == 1) {
+		/* originator */
+		if (force || sta->htpriv.agg_enable_bitmap & BIT(tid)) {
+			sta->htpriv.agg_enable_bitmap &= ~BIT(tid);
+			sta->htpriv.candidate_tid_bitmap &= ~BIT(tid);
+			issue_del_ba(adapter, sta->hwaddr, tid, 37, initiator);
+		}
+	}
+
+exit:
+	return ret;
+}
+
+inline unsigned int send_delba_sta_tid(_adapter *adapter, u8 initiator, struct sta_info *sta, u8 tid
+				       , u8 force)
+{
+	return _send_delba_sta_tid(adapter, initiator, sta, tid, force, 0);
+}
+
+inline unsigned int send_delba_sta_tid_wait_ack(_adapter *adapter, u8 initiator, struct sta_info *sta, u8 tid
+		, u8 force)
+{
+	return _send_delba_sta_tid(adapter, initiator, sta, tid, force, 1);
+}
+
+unsigned int send_delba(_adapter *padapter, u8 initiator, u8 *addr)
+{
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct sta_info *psta = NULL;
+	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;
+
+	for (tid = 0; tid < TID_NUM; tid++)
+		send_delba_sta_tid(padapter, initiator, psta, tid, 0);
+
+	return _SUCCESS;
+}
+
+unsigned int send_beacon(_adapter *padapter)
+{
+	u8	bxmitok = _FALSE;
+	int	issue = 0;
+	int poll = 0;
+#if defined(RTL8814AE_SW_BCN)
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+#endif
+
+	/* bypass TX BCN queue because op ch is switching/waiting */
+	if (check_fwstate(&padapter->mlmepriv, WIFI_OP_CH_SWITCHING)
+	)
+		return _SUCCESS;
+
+	/* RTW_INFO("%s\n", __FUNCTION__); */
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL);
+
+	/* 8192EE Port select for Beacon DL */
+	rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL);
+
+	issue_beacon(padapter, 0);
+
+#ifdef RTL8814AE_SW_BCN
+	if (pHalData->bCorrectBCN != 0)
+		RTW_INFO("%s, line%d, Warnning, pHalData->bCorrectBCN != 0\n", __func__, __LINE__);
+	pHalData->bCorrectBCN = 1;
+#endif
+
+	return _SUCCESS;
+
+}
+
+/****************************************************************************
+
+Following are some utitity fuctions for WiFi MLME
+
+*****************************************************************************/
+
+BOOLEAN IsLegal5GChannel(
+	IN PADAPTER			Adapter,
+	IN u8			channel)
+{
+
+	int i = 0;
+	u8 Channel_5G[45] = {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
+			    };
+	for (i = 0; i < sizeof(Channel_5G); i++)
+		if (channel == Channel_5G[i])
+			return _TRUE;
+	return _FALSE;
+}
+
+/* collect bss info from Beacon and Probe request/response frames. */
+u8 collect_bss_info(_adapter *padapter, union recv_frame *precv_frame, WLAN_BSSID_EX *bssid)
+{
+	int	i;
+	u32	len;
+	u8	*p;
+	u16	val16, subtype;
+	u8	*pframe = precv_frame->u.hdr.rx_data;
+	u32	packet_len = precv_frame->u.hdr.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);
+
+	len = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	if (len > MAX_IE_SZ) {
+		/* RTW_INFO("IE too long for survey event\n"); */
+		return _FAIL;
+	}
+
+	_rtw_memset(bssid, 0, sizeof(WLAN_BSSID_EX));
+
+	subtype = get_frame_sub_type(pframe);
+
+	if (subtype == WIFI_BEACON) {
+		bssid->Reserved[0] = 1;
+		ie_offset = _BEACON_IE_OFFSET_;
+	} else {
+		/* FIXME : more type */
+		if (subtype == WIFI_PROBERSP) {
+			ie_offset = _PROBERSP_IE_OFFSET_;
+			bssid->Reserved[0] = 3;
+		} else if (subtype == WIFI_PROBEREQ) {
+			ie_offset = _PROBEREQ_IE_OFFSET_;
+			bssid->Reserved[0] = 2;
+		} else {
+			bssid->Reserved[0] = 0;
+			ie_offset = _FIXED_IE_LENGTH_;
+		}
+	}
+
+	bssid->Length = sizeof(WLAN_BSSID_EX) - MAX_IE_SZ + len;
+
+	/* below is to copy the information element */
+	bssid->IELength = len;
+	_rtw_memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength);
+
+	/* get the signal strength */
+	/* bssid->Rssi = precv_frame->u.hdr.attrib.SignalStrength; */ /* 0-100 index. */
+	bssid->Rssi = precv_frame->u.hdr.attrib.phy_info.RecvSignalPower; /* in dBM.raw data	 */
+	bssid->PhyInfo.SignalQuality = precv_frame->u.hdr.attrib.phy_info.SignalQuality;/* in percentage */
+	bssid->PhyInfo.SignalStrength = precv_frame->u.hdr.attrib.phy_info.SignalStrength;/* in percentage */
+
+	/* checking SSID */
+	p = rtw_get_ie(bssid->IEs + ie_offset, _SSID_IE_, &len, bssid->IELength - ie_offset);
+	if (p == NULL) {
+		RTW_INFO("marc: cannot find SSID for survey event\n");
+		return _FAIL;
+	}
+
+	if (*(p + 1)) {
+		if (len > NDIS_802_11_LENGTH_SSID) {
+			RTW_INFO("%s()-%d: IE too long (%d) for survey event\n", __FUNCTION__, __LINE__, len);
+			return _FAIL;
+		}
+		_rtw_memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1));
+		bssid->Ssid.SsidLength = *(p + 1);
+	} else
+		bssid->Ssid.SsidLength = 0;
+
+	_rtw_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) {
+			RTW_INFO("%s()-%d: IE too long (%d) for survey event\n", __FUNCTION__, __LINE__, len);
+			return _FAIL;
+		}
+		_rtw_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)) {
+			RTW_INFO("%s()-%d: IE too long (%d) for survey event\n", __FUNCTION__, __LINE__, len);
+			return _FAIL;
+		}
+		_rtw_memcpy(bssid->SupportedRates + i, (p + 2), len);
+	}
+
+	bssid->NetworkTypeInUse = Ndis802_11OFDM24;
+
+	if (subtype == WIFI_PROBEREQ) {
+		u8 *p2p_ie;
+		u32	p2p_ielen;
+		/* Set Listion Channel */
+		p2p_ie = rtw_get_p2p_ie(bssid->IEs, bssid->IELength, NULL, &p2p_ielen);
+		if (p2p_ie) {
+			u32	attr_contentlen = 0;
+			u8 listen_ch[5] = { 0x00 };
+
+			rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_LISTEN_CH, listen_ch, &attr_contentlen);
+			bssid->Configuration.DSConfig = listen_ch[4];
+		} else {
+			/* use current channel */
+			bssid->Configuration.DSConfig = padapter->mlmeextpriv.cur_channel;
+			RTW_INFO("%s()-%d: Cannot get p2p_ie. set DSconfig to op_ch(%d)\n", __FUNCTION__, __LINE__, bssid->Configuration.DSConfig);
+		}
+
+		/* FIXME */
+		bssid->InfrastructureMode = Ndis802_11Infrastructure;
+		_rtw_memcpy(bssid->MacAddress, get_addr2_ptr(pframe), ETH_ALEN);
+		bssid->Privacy = 1;
+		return _SUCCESS;
+	}
+
+	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);
+		}
+	}
+
+	_rtw_memcpy(&bssid->Configuration.BeaconPeriod, rtw_get_beacon_interval_from_ie(bssid->IEs), 2);
+	bssid->Configuration.BeaconPeriod = le32_to_cpu(bssid->Configuration.BeaconPeriod);
+
+	val16 = rtw_get_capability((WLAN_BSSID_EX *)bssid);
+
+	if (val16 & BIT(0)) {
+		bssid->InfrastructureMode = Ndis802_11Infrastructure;
+		_rtw_memcpy(bssid->MacAddress, get_addr2_ptr(pframe), ETH_ALEN);
+	} else {
+		bssid->InfrastructureMode = Ndis802_11IBSS;
+		_rtw_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) && (_FALSE == 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 (pHT_caps->u.HT_cap_element.HT_caps_info & BIT(14))
+				pmlmepriv->num_FortyMHzIntolerant++;
+		} else
+			pmlmepriv->num_sta_no_ht++;
+
+	}
+
+
+	/* mark bss info receving 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(_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);
+	WLAN_BSSID_EX		*pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network));
+	u8 doiqk = _FALSE;
+	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((WLAN_BSSID_EX *)pnetwork);
+	update_capinfo(padapter, caps);
+	if (caps & cap_IBSS) { /* adhoc master */
+		/* set_opmode_cmd(padapter, adhoc); */ /* removed */
+
+		val8 = 0xcf;
+		rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+		doiqk = _TRUE;
+		rtw_hal_set_hwreg(padapter , HW_VAR_DO_IQK , &doiqk);
+
+		/* switch channel */
+		set_channel_bwmode(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
+
+		doiqk = _FALSE;
+		rtw_hal_set_hwreg(padapter , HW_VAR_DO_IQK , &doiqk);
+
+		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) {
+
+			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 {
+		RTW_INFO("start_create_ibss, invalid cap:%x\n", caps);
+		return;
+	}
+	/* update bc/mc sta_info */
+	update_bmc_sta(padapter);
+
+}
+
+void start_clnt_join(_adapter *padapter)
+{
+	unsigned short	caps;
+	u8	val8;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX		*pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network));
+	int beacon_timeout;
+	u8 ASIX_ID[] = {0x00, 0x0E, 0xC6};
+
+	/* update wireless mode */
+	update_wireless_mode(padapter);
+
+	/* udpate capability */
+	caps = rtw_get_capability((WLAN_BSSID_EX *)pnetwork);
+	update_capinfo(padapter, caps);
+
+	/* check if sta is ASIX peer and fix IOT issue if it is. */
+	if (_rtw_memcmp(get_my_bssid(&pmlmeinfo->network) , ASIX_ID , 3)) {
+		u8 iot_flag = _TRUE;
+		rtw_hal_set_hwreg(padapter, HW_VAR_ASIX_IOT, (u8 *)(&iot_flag));
+	}
+
+	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));
+
+#ifdef CONFIG_DEAUTH_BEFORE_CONNECT
+		/* 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. */
+		{
+			_queue *queue = &(padapter->mlmepriv.scanned_queue);
+			_list	*head = get_list_head(queue);
+			_list *pos = get_next(head);
+			struct wlan_network *scanned = NULL;
+			u8 ie_offset = 0;
+			_irqL irqL;
+			bool has_p2p_ie = _FALSE;
+
+			_enter_critical_bh(&(padapter->mlmepriv.scanned_queue.lock), &irqL);
+
+			for (pos = get_next(head); !rtw_end_of_queue_search(head, pos); pos = get_next(pos)) {
+
+				scanned = LIST_CONTAINOR(pos, struct wlan_network, list);
+
+				if (_rtw_memcmp(&(scanned->network.Ssid), &(pnetwork->Ssid), sizeof(NDIS_802_11_SSID)) == _TRUE
+				    && _rtw_memcmp(scanned->network.MacAddress, pnetwork->MacAddress, sizeof(NDIS_802_11_MAC_ADDRESS)) == _TRUE
+				   ) {
+					ie_offset = (scanned->network.Reserved[0] == 2 ? 0 : 12);
+					if (rtw_get_p2p_ie(scanned->network.IEs + ie_offset, scanned->network.IELength - ie_offset, NULL, NULL))
+						has_p2p_ie = _TRUE;
+					break;
+				}
+			}
+
+			_exit_critical_bh(&(padapter->mlmepriv.scanned_queue.lock), &irqL);
+
+			if (scanned == NULL || rtw_end_of_queue_search(head, pos) || has_p2p_ie == _FALSE)
+				/* To avoid connecting to AP fail during resume process, change retry count from 5 to 1 */
+				issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, 1, 100);
+		}
+#endif /* CONFIG_DEAUTH_BEFORE_CONNECT */
+
+		/* 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);
+
+		{
+			rtw_sta_linking_test_set_start();
+			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));
+
+		beacon_timing_control(padapter);
+
+		pmlmeinfo->state = WIFI_FW_ADHOC_STATE;
+
+		report_join_res(padapter, 1);
+	} else {
+		/* RTW_INFO("marc: invalid cap:%x\n", caps); */
+		return;
+	}
+
+}
+
+void start_clnt_auth(_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;
+
+		RTW_PRINT("start auth\n");
+	issue_auth(padapter, NULL, 0);
+
+	set_link_timer(pmlmeext, REAUTH_TO);
+
+}
+
+void start_clnt_assoc(_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(_adapter *padapter, unsigned char *MacAddr, unsigned short reason, u8 locally_generated)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if (!(_rtw_memcmp(MacAddr, get_my_bssid(&pmlmeinfo->network), ETH_ALEN)))
+		return _SUCCESS;
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) {
+		if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) {
+			if (report_del_sta_event(padapter, MacAddr, reason, _TRUE, locally_generated) != _FAIL)
+				pmlmeinfo->state = WIFI_FW_NULL_STATE;
+		} else if (pmlmeinfo->state & WIFI_FW_LINKING_STATE) {
+			if (report_join_res(padapter, -2) != _FAIL)
+				pmlmeinfo->state = WIFI_FW_NULL_STATE;
+		} else
+			RTW_INFO(FUNC_ADPT_FMT" - End to Disconnect\n", FUNC_ADPT_ARG(padapter));
+	}
+
+	return _SUCCESS;
+}
+
+static void process_80211d(PADAPTER padapter, WLAN_BSSID_EX *bssid)
+{
+	struct registry_priv *pregistrypriv;
+	struct mlme_ext_priv *pmlmeext;
+	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;
+		RT_CHANNEL_PLAN chplan_ap;
+		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;
+
+		_rtw_memset(country, 0, 4);
+		_rtw_memcpy(country, p, 3);
+		p += 3;
+		RTW_INFO("%s: 802.11d country=%s\n", __FUNCTION__, 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;
+
+		i = 0;
+		RTW_INFO("%s: AP[%s] channel plan {", __FUNCTION__, bssid->Ssid.Ssid);
+		while ((i < chplan_ap.Len) && (chplan_ap.Channel[i] != 0)) {
+			_RTW_INFO("%02d,", chplan_ap.Channel[i]);
+			i++;
+		}
+		_RTW_INFO("}\n");
+
+		_rtw_memcpy(chplan_sta, pmlmeext->channel_set, sizeof(chplan_sta));
+		i = 0;
+		RTW_INFO("%s: STA channel plan {", __FUNCTION__);
+		while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) {
+			_RTW_INFO("%02d(%c),", chplan_sta[i].ChannelNum, chplan_sta[i].ScanType == SCAN_PASSIVE ? 'p' : 'a');
+			i++;
+		}
+		_RTW_INFO("}\n");
+
+		_rtw_memset(pmlmeext->channel_set, 0, sizeof(pmlmeext->channel_set));
+		chplan_new = pmlmeext->channel_set;
+
+		i = j = 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++;
+		}
+
+		if (pregistrypriv->wireless_mode & WIRELESS_11A) {
+			do {
+				if ((i >= MAX_CHANNEL_NUM)
+				    || (chplan_sta[i].ChannelNum == 0))
+					break;
+
+				if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] == 0))
+					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_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] != 0)) {
+				chplan_new[k].ChannelNum = chplan_ap.Channel[j];
+				chplan_new[k].ScanType = SCAN_ACTIVE;
+				j++;
+				k++;
+			}
+		} else {
+			/* 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;
+
+		k = 0;
+		RTW_INFO("%s: new STA channel plan {", __FUNCTION__);
+		while ((k < MAX_CHANNEL_NUM) && (chplan_new[k].ChannelNum != 0)) {
+			_RTW_INFO("%02d(%c),", chplan_new[k].ChannelNum, chplan_new[k].ScanType == SCAN_PASSIVE ? 'p' : 'c');
+			k++;
+		}
+		_RTW_INFO("}\n");
+	}
+
+	/* 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) {
+				/* 5G Bnad 2, 3 (DFS) doesn't change to active scan */
+				if (rtw_is_dfs_ch(channel))
+					break;
+
+				chplan_new[i].ScanType = SCAN_ACTIVE;
+				RTW_INFO("%s: change channel %d scan type from passive to active\n",
+					 __FUNCTION__, channel);
+			}
+			break;
+		}
+		i++;
+	}
+}
+
+/****************************************************************************
+
+Following are the functions to report events
+
+*****************************************************************************/
+
+void report_survey_event(_adapter *padapter, union 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->u.hdr.rx_data; */
+	/* uint len = precv_frame->u.hdr.len; */
+	int ch_set_idx = -1;
+
+	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) {
+		rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj));
+		return;
+	}
+
+	_rtw_init_listhead(&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, (WLAN_BSSID_EX *)&psurvey_evt->bss) == _FAIL) {
+		rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj));
+		rtw_mfree((u8 *)pevtcmd, cmdsz);
+		return;
+	}
+
+	process_80211d(padapter, &psurvey_evt->bss);
+
+
+	rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
+
+	pmlmeext->sitesurvey_res.bss_cnt++;
+
+	return;
+
+}
+
+void report_surveydone_event(_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) {
+		rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj));
+		return;
+	}
+
+	_rtw_init_listhead(&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;
+
+	RTW_INFO("survey done event(%x) band:%d for "ADPT_FMT"\n", psurveydone_evt->bss_cnt, padapter->setband, ADPT_ARG(padapter));
+
+	rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
+
+	return;
+
+}
+
+u32 report_join_res(_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;
+	u32 ret = _FAIL;
+
+	pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (pcmd_obj == NULL)
+		goto exit;
+
+	cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header));
+	pevtcmd = (u8 *)rtw_zmalloc(cmdsz);
+	if (pevtcmd == NULL) {
+		rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj));
+		goto exit;
+	}
+
+	_rtw_init_listhead(&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));
+	_rtw_memcpy((unsigned char *)(&(pjoinbss_evt->network.network)), &(pmlmeinfo->network), sizeof(WLAN_BSSID_EX));
+	pjoinbss_evt->network.join_res	= pjoinbss_evt->network.aid = res;
+
+	RTW_INFO("report_join_res(%d)\n", res);
+
+	rtw_joinbss_event_prehandle(padapter, (u8 *)&pjoinbss_evt->network);
+
+	ret = rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
+
+exit:
+	return ret;
+}
+
+void report_wmm_edca_update(_adapter *padapter)
+{
+	struct cmd_obj *pcmd_obj;
+	u8	*pevtcmd;
+	u32 cmdsz;
+	struct wmm_event		*pwmm_event;
+	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 wmm_event) + sizeof(struct C2HEvent_Header));
+	pevtcmd = (u8 *)rtw_zmalloc(cmdsz);
+	if (pevtcmd == NULL) {
+		rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj));
+		return;
+	}
+
+	_rtw_init_listhead(&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 wmm_event);
+	pc2h_evt_hdr->ID = GEN_EVT_CODE(_WMM);
+	pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq);
+
+	pwmm_event = (struct wmm_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
+	pwmm_event->wmm = 0;
+
+	rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
+
+	return;
+
+}
+
+u32 report_del_sta_event(_adapter *padapter, unsigned char *MacAddr, unsigned short reason, bool enqueue, u8 locally_generated)
+{
+	struct cmd_obj *pcmd_obj;
+	u8	*pevtcmd;
+	u32 cmdsz;
+	struct sta_info *psta;
+	int	mac_id = -1;
+	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;
+	u8 res = _SUCCESS;
+
+	/* prepare cmd parameter */
+	cmdsz = (sizeof(struct stadel_event) + sizeof(struct C2HEvent_Header));
+	pevtcmd = (u8 *)rtw_zmalloc(cmdsz);
+	if (pevtcmd == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	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));
+	_rtw_memcpy((unsigned char *)(&(pdel_sta_evt->macaddr)), MacAddr, ETH_ALEN);
+	_rtw_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;
+	pdel_sta_evt->locally_generated = locally_generated;
+
+	if (!enqueue) {
+		/* do directly */
+		rtw_stadel_event_callback(padapter, (u8 *)pdel_sta_evt);
+		rtw_mfree(pevtcmd, cmdsz);
+	} else {
+		pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+		if (pcmd_obj == NULL) {
+			rtw_mfree(pevtcmd, cmdsz);
+			res = _FAIL;
+			goto exit;
+		}
+
+		_rtw_init_listhead(&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;
+
+		res = rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
+	}
+
+exit:
+
+	RTW_INFO(FUNC_ADPT_FMT" "MAC_FMT" mac_id=%d, enqueue:%d, res:%u\n"
+		, FUNC_ADPT_ARG(padapter), MAC_ARG(MacAddr), mac_id, enqueue, res);
+
+	return res;
+}
+
+void report_add_sta_event(_adapter *padapter, unsigned char *MacAddr)
+{
+	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) {
+		rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj));
+		return;
+	}
+
+	_rtw_init_listhead(&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));
+	_rtw_memcpy((unsigned char *)(&(padd_sta_evt->macaddr)), MacAddr, ETH_ALEN);
+
+	RTW_INFO("report_add_sta_event: add STA\n");
+
+	rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
+
+	return;
+}
+
+bool rtw_port_switch_chk(_adapter *adapter)
+{
+	bool switch_needed = _FALSE;
+	return switch_needed;
+}
+
+/****************************************************************************
+
+Following are the event callback functions
+
+*****************************************************************************/
+
+/* for sta/adhoc mode */
+void update_sta_info(_adapter *padapter, struct sta_info *psta)
+{
+	_irqL	irqL;
+	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;
+
+		psta->htpriv.rx_ampdu_min_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2;
+
+		if (support_short_GI(padapter, &(pmlmeinfo->HT_caps), CHANNEL_WIDTH_20))
+			psta->htpriv.sgi_20m = _TRUE;
+
+		if (support_short_GI(padapter, &(pmlmeinfo->HT_caps), CHANNEL_WIDTH_40))
+			psta->htpriv.sgi_40m = _TRUE;
+
+		psta->qos_option = _TRUE;
+
+		psta->htpriv.ldpc_cap = pmlmepriv->htpriv.ldpc_cap;
+		psta->htpriv.stbc_cap = pmlmepriv->htpriv.stbc_cap;
+		psta->htpriv.beamform_cap = pmlmepriv->htpriv.beamform_cap;
+
+		_rtw_memcpy(&psta->htpriv.ht_cap, &pmlmeinfo->HT_caps, sizeof(struct rtw_ieee80211_ht_cap));
+	} else
+	{
+		psta->htpriv.ht_option = _FALSE;
+		psta->htpriv.ampdu_enable = _FALSE;
+		psta->htpriv.tx_amsdu_enable = _FALSE;
+		psta->htpriv.sgi_20m = _FALSE;
+		psta->htpriv.sgi_40m = _FALSE;
+		psta->qos_option = _FALSE;
+
+	}
+
+	psta->htpriv.ch_offset = pmlmeext->cur_ch_offset;
+
+	psta->htpriv.agg_enable_bitmap = 0x0;/* reset */
+	psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */
+
+	psta->bw_mode = pmlmeext->cur_bwmode;
+
+	/* QoS */
+	if (pmlmepriv->qospriv.qos_option)
+		psta->qos_option = _TRUE;
+
+	_rtw_memcpy(&psta->vhtpriv, &pmlmepriv->vhtpriv, sizeof(struct vht_priv));
+
+	update_ldpc_stbc_cap(psta);
+
+	_enter_critical_bh(&psta->lock, &irqL);
+	psta->state = _FW_LINKED;
+	_exit_critical_bh(&psta->lock, &irqL);
+
+}
+
+static void rtw_mlmeext_disconnect(_adapter *padapter)
+{
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX		*pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network));
+	u8 state_backup = (pmlmeinfo->state & 0x03);
+	u8 ASIX_ID[] = {0x00, 0x0E, 0xC6};
+
+	/* set_opmode_cmd(padapter, infra_client_with_mlme); */
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, 0);
+	rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr);
+
+	/* set MSR to no link state->infra. mode */
+	Set_MSR(padapter, _HW_STATE_STATION_);
+
+	/* check if sta is ASIX peer and fix IOT issue if it is. */
+	if (_rtw_memcmp(get_my_bssid(&pmlmeinfo->network) , ASIX_ID , 3)) {
+		u8 iot_flag = _FALSE;
+		rtw_hal_set_hwreg(padapter, HW_VAR_ASIX_IOT, (u8 *)(&iot_flag));
+	}
+	pmlmeinfo->state = WIFI_FW_NULL_STATE;
+
+	if (state_backup == WIFI_FW_STATION_STATE) {
+		if (rtw_port_switch_chk(padapter) == _TRUE) {
+			rtw_hal_set_hwreg(padapter, HW_VAR_PORT_SWITCH, NULL);
+			{
+				_adapter *port0_iface = dvobj_get_port0_adapter(adapter_to_dvobj(padapter));
+				if (port0_iface)
+					rtw_lps_ctrl_wk_cmd(port0_iface, LPS_CTRL_CONNECT, 0);
+			}
+		}
+	}
+
+	/* switch to the 20M Hz mode after disconnect */
+	pmlmeext->cur_bwmode = CHANNEL_WIDTH_20;
+	pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+#ifdef CONFIG_FCS_MODE
+	if (EN_FCS(padapter))
+		rtw_hal_set_hwreg(padapter, HW_VAR_STOP_FCS_MODE, NULL);
+#endif
+
+
+	{
+		u8 ch, bw, offset;
+
+		if (rtw_mi_get_ch_setting_union_no_self(padapter, &ch, &bw, &offset) != 0) {
+			set_channel_bwmode(padapter, ch, offset, bw);
+			rtw_mi_update_union_chan_inf(padapter, ch, offset, bw);
+		}
+	}
+
+	flush_all_cam_entry(padapter);
+
+	_cancel_timer_ex(&pmlmeext->link_timer);
+
+	/* pmlmepriv->LinkDetectInfo.TrafficBusyState = _FALSE; */
+	pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0;
+	pmlmepriv->LinkDetectInfo.LowPowerTransitionCount = 0;
+
+}
+
+void mlmeext_joinbss_event_callback(_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);
+	WLAN_BSSID_EX		*cur_network = &(pmlmeinfo->network);
+	struct sta_priv		*pstapriv = &padapter->stapriv;
+	u8	join_type;
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+	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);
+
+		goto exit_mlmeext_joinbss_event_callback;
+	}
+
+	if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) {
+		/* update bc/mc sta_info */
+		update_bmc_sta(padapter);
+	}
+
+	/* 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);
+
+	/* VHT */
+	VHTOnAssocRsp(padapter);
+
+	psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress);
+	if (psta) { /* only for infra. mode */
+		/* RTW_INFO("set_sta_rate\n"); */
+
+		psta->wireless_mode = pmlmeext->cur_wireless_mode;
+
+
+		/* set per sta rate after updating HT cap. */
+		set_sta_rate(padapter, psta);
+
+		rtw_sta_media_status_rpt(padapter, psta, 1);
+
+		/* wakeup macid after join bss successfully to ensure
+			the subsequent data frames can be sent out normally */
+		rtw_hal_macid_wakeup(padapter, psta->mac_id);
+	}
+
+	if (is_wep_enc(psecuritypriv->dot11PrivacyAlgrthm))
+		rtw_sec_restore_wep_key(padapter);
+
+	if (rtw_port_switch_chk(padapter) == _TRUE)
+		rtw_hal_set_hwreg(padapter, HW_VAR_PORT_SWITCH, NULL);
+
+	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);
+
+		/* set_link_timer(pmlmeext, DISCONNECT_TO); */
+	}
+
+	if (get_hw_port(padapter) == HW_PORT0)
+		rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_CONNECT, 0);
+
+
+exit_mlmeext_joinbss_event_callback:
+
+	rtw_join_done_chk_ch(padapter, join_res);
+
+	RTW_INFO("=>%s - End to Connection without 4-way\n", __FUNCTION__);
+}
+
+/* currently only adhoc mode will go here */
+void mlmeext_sta_add_event_callback(_adapter *padapter, struct sta_info *psta)
+{
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8	join_type;
+
+	RTW_INFO("%s\n", __FUNCTION__);
+
+	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 */
+			/* update TSF Value */
+			/* update_TSF(pmlmeext, pframe, len);			 */
+
+			/* correcting TSF */
+			correct_TSF(padapter, pmlmeext);
+
+			/* start beacon */
+			if (send_beacon(padapter) == _FAIL)
+				rtw_warn_on(1);
+
+			pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS;
+		}
+
+		join_type = 2;
+		rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+	}
+
+	/* update adhoc sta_info */
+	update_sta_info(padapter, psta);
+
+	rtw_hal_update_sta_rate_mask(padapter, psta);
+
+	/* ToDo: HT for Ad-hoc */
+	psta->wireless_mode = rtw_check_network_type(psta->bssrateset, psta->bssratelen, pmlmeext->cur_channel);
+	psta->raid = rtw_hal_networktype_to_raid(padapter, psta);
+
+	/* rate radaptive */
+	Update_RA_Entry(padapter, psta);
+}
+
+void mlmeext_sta_del_event_callback(_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_mlmeext_disconnect(padapter);
+
+}
+
+/****************************************************************************
+
+Following are the functions for the timer handlers
+
+*****************************************************************************/
+void _linked_info_dump(_adapter *padapter)
+{
+	int i;
+	struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info    *pmlmeinfo = &(pmlmeext->mlmext_info);
+	HAL_DATA_TYPE *HalData = GET_HAL_DATA(padapter);
+	int undecorated_smoothed_pwdb = 0;
+
+	if (padapter->bLinkInfoDump) {
+
+		RTW_INFO("\n============["ADPT_FMT"] linked status check ===================\n", ADPT_ARG(padapter));
+
+		if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) {
+			rtw_hal_get_def_var(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &undecorated_smoothed_pwdb);
+
+			RTW_INFO("AP[" MAC_FMT "] - undecorated_smoothed_pwdb:%d\n",
+				MAC_ARG(padapter->mlmepriv.cur_network.network.MacAddress), undecorated_smoothed_pwdb);
+		} else if ((pmlmeinfo->state & 0x03) == _HW_STATE_AP_) {
+			_irqL irqL;
+			_list	*phead, *plist;
+
+			struct sta_info *psta = NULL;
+			struct sta_priv *pstapriv = &padapter->stapriv;
+
+			_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+			phead = &pstapriv->asoc_list;
+			plist = get_next(phead);
+			while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+				psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+				plist = get_next(plist);
+
+				RTW_INFO("STA[" MAC_FMT "]:undecorated_smoothed_pwdb:%d\n",
+					MAC_ARG(psta->hwaddr), psta->rssi_stat.undecorated_smoothed_pwdb);
+			}
+			_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+		}
+
+		/*============  tx info ============	*/
+		rtw_hal_get_def_var(padapter, HW_DEF_RA_INFO_DUMP, RTW_DBGDUMP);
+
+		rtw_hal_set_odm_var(padapter, HAL_ODM_RX_INFO_DUMP, RTW_DBGDUMP, _FALSE);
+
+	}
+
+}
+/********************************************************************
+
+When station does not receive any packet in MAX_CONTINUAL_NORXPACKET_COUNT*2 seconds,
+recipient station will teardown the block ack by issuing DELBA frame.
+
+*********************************************************************/
+void rtw_delba_check(_adapter *padapter, struct sta_info *psta, u8 from_timer)
+{
+	int	i = 0;
+	int ret = _SUCCESS;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	/*
+		IOT issue,occur Broadcom ap(Buffalo WZR-D1800H,Netgear R6300).
+		AP is originator.AP does not transmit unicast packets when STA response its BAR.
+		This case probably occur ap issue BAR after AP builds BA.
+
+		Follow 802.11 spec, STA shall maintain an inactivity timer for every negotiated Block Ack setup.
+		The inactivity timer is not reset when MPDUs corresponding to other TIDs are received.
+	*/
+	if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_BROADCOM) {
+		for (i = 0; i < TID_NUM ; i++) {
+			if ((psta->recvreorder_ctrl[i].enable) && 
+                        (sta_rx_data_qos_pkts(psta, i) == sta_last_rx_data_qos_pkts(psta, i)) ) {			
+					if (_TRUE == rtw_inc_and_chk_continual_no_rx_packet(psta, i)) {					
+						/* send a DELBA frame to the peer STA with the Reason Code field set to TIMEOUT */
+						if (!from_timer)
+							ret = issue_del_ba_ex(padapter, psta->hwaddr, i, 39, 0, 3, 1);
+						else
+							issue_del_ba(padapter,  psta->hwaddr, i, 39, 0);
+						psta->recvreorder_ctrl[i].enable = _FALSE;
+						if (ret != _FAIL)
+							psta->recvreorder_ctrl[i].ampdu_size = RX_AMPDU_SIZE_INVALID;
+						rtw_reset_continual_no_rx_packet(psta, i);
+					}				
+			} else {
+				/* The inactivity timer is reset when MPDUs to the TID is received. */
+				rtw_reset_continual_no_rx_packet(psta, i);
+			}
+		}
+	}
+}
+
+u8 chk_ap_is_alive(_adapter *padapter, struct sta_info *psta)
+{
+	u8 ret = _FALSE;
+	int i = 0;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+
+	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);
+
+	/*
+		record last rx data packets for every tid.
+	*/
+	for (i = 0; i < TID_NUM; i++)
+		psta->sta_stats.last_rx_data_qos_pkts[i] = psta->sta_stats.rx_data_qos_pkts[i];
+
+	return ret;
+}
+
+u8 chk_adhoc_peer_is_alive(struct sta_info *psta)
+{
+	u8 ret = _TRUE;
+
+
+	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;
+
+	sta_update_last_rx_pkts(psta);
+
+	return ret;
+}
+
+/* from_timer == 1 means driver is in LPS */
+void linked_status_chk(_adapter *padapter, u8 from_timer)
+{
+	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;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct recv_priv	*precvpriv = &padapter->recvpriv;
+
+	if (padapter->registrypriv.mp_mode == _TRUE)
+		return;
+
+	if (is_client_associated_to_ap(padapter)) {
+		/* linked infrastructure client mode */
+
+		int tx_chk = _SUCCESS, rx_chk = _SUCCESS;
+		int rx_chk_limit;
+		int link_count_limit;
+
+		if (rtw_chk_roam_flags(padapter, RTW_ROAM_ACTIVE)) {
+			RTW_INFO("signal_strength_data.avg_val = %d\n", precvpriv->signal_strength_data.avg_val);
+			if (precvpriv->signal_strength_data.avg_val < pmlmepriv->roam_rssi_threshold) {
+				pmlmepriv->need_to_roam = _TRUE;
+				rtw_drv_scan_by_self(padapter, RTW_AUTO_SCAN_REASON_ROAM);
+			} else {
+				pmlmepriv->need_to_roam = _FALSE;
+			}
+		}
+
+#if defined(DBG_ROAMING_TEST)
+		rx_chk_limit = 1;
+#else
+		rx_chk_limit = 4;
+#endif
+		if (!rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE)) {
+			if (!from_timer)
+				link_count_limit = 3; /* 8 sec */
+			else
+				link_count_limit = 15; /* 32 sec */
+		} else
+		{
+			if (!from_timer)
+				link_count_limit = 7; /* 16 sec */
+			else
+				link_count_limit = 29; /* 60 sec */
+		}
+
+		psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress);
+		if (psta != NULL) {
+			bool is_p2p_enable = _FALSE;
+			is_p2p_enable = !rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE);
+
+#ifdef CONFIG_ISSUE_DELBA_WHEN_NO_TRAFFIC 
+			/*issue delba when ap does not tx data packet that is Broadcom ap */
+			rtw_delba_check(padapter, psta, from_timer);
+#endif
+			if (chk_ap_is_alive(padapter, psta) == _FALSE)
+				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_ch = 0, backup_bw, backup_offset;
+				u8 union_ch = 0, union_bw, union_offset;
+
+				if (!rtw_mi_get_ch_setting_union(padapter, &union_ch, &union_bw, &union_offset)
+					|| pmlmeext->cur_channel != union_ch)
+						goto bypass_active_keep_alive;
+
+				/* switch to correct channel of current network  before issue keep-alive frames */
+				if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) {
+					backup_ch = rtw_get_oper_ch(padapter);
+					backup_bw = rtw_get_oper_bw(padapter);
+					backup_offset = rtw_get_oper_choffset(padapter);
+					set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
+				}
+
+				if (rx_chk != _SUCCESS)
+					issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, psta->hwaddr, 0, 0, 3, 1);
+
+				if ((tx_chk != _SUCCESS && pmlmeinfo->link_count++ == link_count_limit) || 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_ch > 0)
+					set_channel_bwmode(padapter, backup_ch, backup_offset, backup_bw);
+
+bypass_active_keep_alive:
+				;
+			} else
+			{
+				if (rx_chk != _SUCCESS) {
+					if (pmlmeext->retry == 0) {
+						issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress, 0, 0, 0, 0);
+						issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress, 0, 0, 0, 0);
+						issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress, 0, 0, 0, 0);
+					}
+				}
+
+				if (tx_chk != _SUCCESS && pmlmeinfo->link_count++ == link_count_limit
+				   ) {
+					tx_chk = issue_nulldata_in_interrupt(padapter, NULL, from_timer ? 1 : 0);
+				}
+			}
+
+			if (rx_chk == _FAIL) {
+				pmlmeext->retry++;
+				if (pmlmeext->retry > rx_chk_limit) {
+					RTW_PRINT(FUNC_ADPT_FMT" disconnect or roaming\n",
+						  FUNC_ADPT_ARG(padapter));
+					receive_disconnect(padapter, pmlmeinfo->network.MacAddress
+						, WLAN_REASON_EXPIRATION_CHK, _FALSE);
+					return;
+				}
+			} else
+				pmlmeext->retry = 0;
+
+			if (tx_chk == _FAIL)
+				pmlmeinfo->link_count %= (link_count_limit + 1);
+			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)) {
+		_irqL irqL;
+		_list *phead, *plist, dlist;
+
+		_rtw_init_listhead(&dlist);
+
+		_enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+		for (i = 0; i < NUM_STA; i++) {
+
+			phead = &(pstapriv->sta_hash[i]);
+			plist = get_next(phead);
+			while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+				psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+				plist = get_next(plist);
+
+				if (is_broadcast_mac_addr(psta->hwaddr))
+					continue;
+
+				if (chk_adhoc_peer_is_alive(psta) || !psta->expire_to)
+					psta->expire_to = pstapriv->adhoc_expire_to;
+				else
+					psta->expire_to--;
+
+				if (psta->expire_to <= 0) {
+					rtw_list_delete(&psta->list);
+					rtw_list_insert_tail(&psta->list, &dlist);
+				}
+			}
+		}
+
+		_exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+		plist = get_next(&dlist);
+		while (rtw_end_of_queue_search(&dlist, plist) == _FALSE) {
+			psta = LIST_CONTAINOR(plist, struct sta_info, list);
+			plist = get_next(plist);
+			rtw_list_delete(&psta->list);
+			RTW_INFO(FUNC_ADPT_FMT" ibss expire "MAC_FMT"\n"
+				, FUNC_ADPT_ARG(padapter), MAC_ARG(psta->hwaddr));
+			report_del_sta_event(padapter, psta->hwaddr, WLAN_REASON_EXPIRATION_CHK, from_timer ? _TRUE : _FALSE, _FALSE);
+		}
+	}
+
+}
+
+void survey_timer_hdl(void *ctx)
+{
+	_adapter *padapter = (_adapter *)ctx;
+	struct cmd_obj *cmd;
+	struct sitesurvey_parm *psurveyPara;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	if (mlmeext_scan_state(pmlmeext) > SCAN_DISABLE) {
+		cmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+		if (cmd == NULL) {
+			rtw_warn_on(1);
+			goto exit;
+		}
+
+		psurveyPara = (struct sitesurvey_parm *)rtw_zmalloc(sizeof(struct sitesurvey_parm));
+		if (psurveyPara == NULL) {
+			rtw_warn_on(1);
+			rtw_mfree((unsigned char *)cmd, sizeof(struct cmd_obj));
+			goto exit;
+		}
+
+		init_h2fwcmd_w_parm_no_rsp(cmd, psurveyPara, GEN_CMD_CODE(_SiteSurvey));
+		rtw_enqueue_cmd(pcmdpriv, cmd);
+	}
+
+exit:
+	return;
+}
+
+void link_timer_hdl(void *ctx)
+{
+	_adapter *padapter = (_adapter *)ctx;
+	/* static unsigned int		rx_pkt = 0; */
+	/* static u64				tx_cnt = 0; */
+	/* 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 (rtw_sta_linking_test_force_fail())
+		RTW_INFO("rtw_sta_linking_test_force_fail\n");
+
+	if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) {
+		RTW_INFO("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) {
+			/* if (pmlmeinfo->auth_algo != dot11AuthAlgrthm_Auto) */
+			/* { */
+			pmlmeinfo->state = 0;
+			report_join_res(padapter, -1);
+			return;
+			/* } */
+			/* else */
+			/* { */
+			/*	pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; */
+			/*	pmlmeinfo->reauth_count = 0; */
+			/* } */
+		}
+
+		RTW_INFO("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;
+		}
+
+		{
+			RTW_INFO("link_timer_hdl: assoc timeout and try again\n");
+			issue_assocreq(padapter);
+		}
+
+		set_link_timer(pmlmeext, REASSOC_TO);
+	}
+
+	return;
+}
+
+void addba_timer_hdl(void *ctx)
+{
+	struct sta_info *psta = (struct sta_info *)ctx;
+
+	struct ht_priv	*phtpriv;
+
+	if (!psta)
+		return;
+
+	phtpriv = &psta->htpriv;
+
+	if ((phtpriv->ht_option == _TRUE) && (phtpriv->ampdu_enable == _TRUE)) {
+		if (phtpriv->candidate_tid_bitmap)
+			phtpriv->candidate_tid_bitmap = 0x0;
+
+	}
+}
+
+
+
+u8 NULL_hdl(_adapter *padapter, u8 *pbuf)
+{
+	return H2C_SUCCESS;
+}
+
+
+u8 setopmode_hdl(_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_;
+		/* start_ap_mode(padapter); */
+	} 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 if (psetop->mode == Ndis802_11Monitor)
+		type = _HW_STATE_MONITOR_;
+	else
+		type = _HW_STATE_NOLINK_;
+
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type));
+
+
+	if (rtw_port_switch_chk(padapter) == _TRUE) {
+		rtw_hal_set_hwreg(padapter, HW_VAR_PORT_SWITCH, NULL);
+
+		if (psetop->mode == Ndis802_11APMode)
+			adapter_to_pwrctl(padapter)->fw_psmode_iface_id = 0xff; /* ap mode won't dowload rsvd pages */
+		else if (psetop->mode == Ndis802_11Infrastructure) {
+			_adapter *port0_iface = dvobj_get_port0_adapter(adapter_to_dvobj(padapter));
+			if (port0_iface)
+				rtw_lps_ctrl_wk_cmd(port0_iface, LPS_CTRL_CONNECT, 0);
+		}
+	}
+
+	if (psetop->mode == Ndis802_11APMode ||
+		psetop->mode == Ndis802_11Monitor) {
+		/* Do this after port switch to */
+		/* prevent from downloading rsvd page to wrong port */
+		rtw_btcoex_MediaStatusNotify(padapter, 1); /* connect */
+	}
+
+	return H2C_SUCCESS;
+
+}
+
+u8 createbss_hdl(_adapter *padapter, u8 *pbuf)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX	*pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network));
+	WLAN_BSSID_EX	*pdev_network = &padapter->registrypriv.dev_network;
+	struct createbss_parm *parm = (struct createbss_parm *)pbuf;
+	u8 ret = H2C_SUCCESS;
+	/* u8	initialgain; */
+
+	if (pmlmeinfo->state == WIFI_FW_AP_STATE) {
+		start_bss_network(padapter, parm);
+		goto exit;
+	}
+
+	/* below is for ad-hoc master */
+	if (parm->adhoc) {
+		rtw_warn_on(pdev_network->InfrastructureMode != Ndis802_11IBSS);
+		rtw_joinbss_reset(padapter);
+
+		pmlmeext->cur_bwmode = 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;
+
+		/* config the initial gain under linking, need to write the BB registers */
+		/* initialgain = 0x1E; */
+		/*rtw_hal_set_odm_var(padapter, HAL_ODM_INITIAL_GAIN, &initialgain, _FALSE);*/
+
+		/* disable dynamic functions, such as high power, DIG */
+		rtw_phydm_ability_backup(padapter);
+		rtw_phydm_func_disable_all(padapter);
+
+		/* cancel link timer */
+		_cancel_timer_ex(&pmlmeext->link_timer);
+
+		/* clear CAM */
+		flush_all_cam_entry(padapter);
+
+		pdev_network->Length = get_WLAN_BSSID_EX_sz(pdev_network);
+		_rtw_memcpy(pnetwork, pdev_network, FIELD_OFFSET(WLAN_BSSID_EX, IELength));
+		pnetwork->IELength = pdev_network->IELength;
+
+		if (pnetwork->IELength > MAX_IE_SZ) {
+			ret = H2C_PARAMETERS_ERROR;
+			goto ibss_post_hdl;
+		}
+
+		_rtw_memcpy(pnetwork->IEs, pdev_network->IEs, pnetwork->IELength);
+		start_create_ibss(padapter);
+	} else {
+		rtw_warn_on(1);
+		ret = H2C_PARAMETERS_ERROR;
+	}
+
+ibss_post_hdl:
+	rtw_create_ibss_post_hdl(padapter, ret);
+
+exit:
+	return ret;
+}
+
+u8 join_cmd_hdl(_adapter *padapter, u8 *pbuf)
+{
+	u8	join_type;
+	PNDIS_802_11_VARIABLE_IEs	pIE;
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX		*pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network));
+	u32 i;
+	/* u8	initialgain; */
+	/* u32	acparm; */
+	u8 u_ch, u_bw, u_offset;
+	u8 doiqk = _FALSE;
+
+	/* 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, 1, 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_NOLINK_); */
+		Set_MSR(padapter, _HW_STATE_STATION_);
+
+		rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, 0);
+	}
+
+
+	rtw_joinbss_reset(padapter);
+
+	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;
+	/* pmlmeinfo->assoc_AP_vendor = HT_IOT_PEER_MAX; */
+	pmlmeinfo->VHT_enable = 0;
+
+	_rtw_memcpy(pnetwork, pbuf, FIELD_OFFSET(WLAN_BSSID_EX, IELength));
+	pnetwork->IELength = ((WLAN_BSSID_EX *)pbuf)->IELength;
+
+	if (pnetwork->IELength > MAX_IE_SZ) /* Check pbuf->IELength */
+		return H2C_PARAMETERS_ERROR;
+
+	if (pnetwork->IELength < 2) {
+		report_join_res(padapter, (-4));
+		return H2C_SUCCESS;
+	}
+	_rtw_memcpy(pnetwork->IEs, ((WLAN_BSSID_EX *)pbuf)->IEs, pnetwork->IELength);
+
+	pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork);
+
+	/* Check AP vendor to move rtw_joinbss_cmd() */
+	/* pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->IEs, pnetwork->IELength); */
+
+	/* sizeof(NDIS_802_11_FIXED_IEs)	 */
+	for (i = _FIXED_IE_LENGTH_ ; i < pnetwork->IELength - 2 ;) {
+		pIE = (PNDIS_802_11_VARIABLE_IEs)(pnetwork->IEs + i);
+
+		switch (pIE->ElementID) {
+		case _VENDOR_SPECIFIC_IE_: /* Get WMM IE. */
+			if (_rtw_memcmp(pIE->data, WMM_OUI, 4))
+				WMM_param_handler(padapter, pIE);
+			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;
+			break;
+
+		case EID_VHTCapability: /* Get VHT Cap IE. */
+			pmlmeinfo->VHT_enable = 1;
+			break;
+
+		case EID_VHTOperation: /* Get VHT Operation IE. */
+			break;
+		default:
+			break;
+		}
+
+		i += (pIE->Length + 2);
+	}
+
+	rtw_bss_get_chbw(pnetwork
+		, &pmlmeext->cur_channel, &pmlmeext->cur_bwmode, &pmlmeext->cur_ch_offset);
+
+	rtw_adjust_chbw(padapter, pmlmeext->cur_channel, &pmlmeext->cur_bwmode, &pmlmeext->cur_ch_offset);
+
+	/* check channel, bandwidth, offset and switch */
+	if (rtw_chk_start_clnt_join(padapter, &u_ch, &u_bw, &u_offset) == _FAIL) {
+		report_join_res(padapter, (-4));
+		return H2C_SUCCESS;
+	}
+
+	/* disable dynamic functions, such as high power, DIG */
+	/*rtw_phydm_func_disable_all(padapter);*/
+
+	/* config the initial gain under linking, need to write the BB registers */
+	/* initialgain = 0x1E; */
+	/*rtw_hal_set_odm_var(padapter, HAL_ODM_INITIAL_GAIN, &initialgain, _FALSE);*/
+
+	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));
+	doiqk = _TRUE;
+	rtw_hal_set_hwreg(padapter , HW_VAR_DO_IQK , &doiqk);
+
+	set_channel_bwmode(padapter, u_ch, u_offset, u_bw);
+	rtw_mi_update_union_chan_inf(padapter, u_ch, u_offset, u_bw);
+
+	doiqk = _FALSE;
+	rtw_hal_set_hwreg(padapter , HW_VAR_DO_IQK , &doiqk);
+
+	/* cancel link timer */
+	_cancel_timer_ex(&pmlmeext->link_timer);
+
+	start_clnt_join(padapter);
+
+	return H2C_SUCCESS;
+
+}
+
+u8 disconnect_hdl(_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);
+	WLAN_BSSID_EX		*pnetwork = (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);
+	}
+
+
+	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));
+	}
+
+	rtw_mlmeext_disconnect(padapter);
+
+	rtw_free_uc_swdec_pending_queue(padapter);
+
+	rtw_sta_mstatus_report(padapter);
+
+	return	H2C_SUCCESS;
+}
+
+static const char *const _scan_state_str[] = {
+	"SCAN_DISABLE",
+	"SCAN_START",
+	"SCAN_PS_ANNC_WAIT",
+	"SCAN_ENTER",
+	"SCAN_PROCESS",
+	"SCAN_BACKING_OP",
+	"SCAN_BACK_OP",
+	"SCAN_LEAVING_OP",
+	"SCAN_LEAVE_OP",
+	"SCAN_SW_ANTDIV_BL",
+	"SCAN_TO_P2P_LISTEN",
+	"SCAN_P2P_LISTEN",
+	"SCAN_COMPLETE",
+	"SCAN_STATE_MAX",
+};
+
+const char *scan_state_str(u8 state)
+{
+	state = (state >= SCAN_STATE_MAX) ? SCAN_STATE_MAX : state;
+	return _scan_state_str[state];
+}
+
+static bool scan_abort_hdl(_adapter *adapter)
+{
+	struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct ss_res *ss = &pmlmeext->sitesurvey_res;
+	struct wifidirect_info *pwdinfo = &adapter->wdinfo;
+	bool ret = _FALSE;
+
+	if (pmlmeext->scan_abort == _TRUE) {
+		if (!rtw_p2p_chk_state(&adapter->wdinfo, P2P_STATE_NONE)) {
+			rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX);
+			ss->channel_idx = 3;
+			RTW_INFO("%s idx:%d, cnt:%u\n", __FUNCTION__
+				 , ss->channel_idx
+				 , pwdinfo->find_phase_state_exchange_cnt
+				);
+		} else
+		{
+			ss->channel_idx = ss->ch_num;
+			RTW_INFO("%s idx:%d\n", __FUNCTION__
+				 , ss->channel_idx
+				);
+		}
+		pmlmeext->scan_abort = _FALSE;
+		ret = _TRUE;
+	}
+
+	return ret;
+}
+
+u8 rtw_scan_sparse(_adapter *adapter, struct rtw_ieee80211_channel *ch, u8 ch_num)
+{
+	/* interval larger than this is treated as backgroud scan */
+#ifndef RTW_SCAN_SPARSE_BG_INTERVAL_MS
+#define RTW_SCAN_SPARSE_BG_INTERVAL_MS 12000
+#endif
+
+#ifndef RTW_SCAN_SPARSE_CH_NUM_MIRACAST
+#define RTW_SCAN_SPARSE_CH_NUM_MIRACAST 1
+#endif
+#ifndef RTW_SCAN_SPARSE_CH_NUM_BG
+#define RTW_SCAN_SPARSE_CH_NUM_BG 4
+#endif
+#ifndef RTW_SCAN_SPARSE_CH_NUM_ROAMING_ACTIVE
+#define RTW_SCAN_SPARSE_CH_NUM_ROAMING_ACTIVE 1
+#endif
+
+#define SCAN_SPARSE_CH_NUM_INVALID 255
+
+	static u8 token = 255;
+	u32 interval;
+	bool busy_traffic = _FALSE;
+	bool miracast_enabled = _FALSE;
+	bool bg_scan = _FALSE;
+	u8 max_allow_ch = SCAN_SPARSE_CH_NUM_INVALID;
+	u8 scan_division_num;
+	u8 ret_num = ch_num;
+	struct registry_priv *regsty = dvobj_to_regsty(adapter_to_dvobj(adapter));
+	struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+
+	if (regsty->wifi_spec)
+		goto exit;
+
+	/* assume ch_num > 6 is normal scan */
+	if (ch_num <= 6)
+		goto exit;
+
+	if (mlmeext->last_scan_time == 0)
+		mlmeext->last_scan_time = rtw_get_current_time();
+
+	interval = rtw_get_passing_time_ms(mlmeext->last_scan_time);
+
+	if (rtw_mi_busy_traffic_check(adapter, _FALSE))
+		busy_traffic = _TRUE;
+
+	if (rtw_mi_check_miracast_enabled(adapter))
+		miracast_enabled = _TRUE;
+
+	if (interval > RTW_SCAN_SPARSE_BG_INTERVAL_MS)
+		bg_scan = _TRUE;
+
+	/* max_allow_ch by conditions*/
+
+#if RTW_SCAN_SPARSE_MIRACAST
+	if (miracast_enabled == _TRUE && busy_traffic == _TRUE)
+		max_allow_ch = rtw_min(max_allow_ch, RTW_SCAN_SPARSE_CH_NUM_MIRACAST);
+#endif
+
+#if RTW_SCAN_SPARSE_BG
+	if (bg_scan == _TRUE)
+		max_allow_ch = rtw_min(max_allow_ch, RTW_SCAN_SPARSE_CH_NUM_BG);
+#endif
+
+#if defined(RTW_SCAN_SPARSE_ROAMING_ACTIVE)
+	if (rtw_chk_roam_flags(adapter, RTW_ROAM_ACTIVE)) {
+		if (busy_traffic == _TRUE && adapter->mlmepriv.need_to_roam == _TRUE)
+			max_allow_ch = rtw_min(max_allow_ch, RTW_SCAN_SPARSE_CH_NUM_ROAMING_ACTIVE);
+	}
+#endif
+
+	if (max_allow_ch != SCAN_SPARSE_CH_NUM_INVALID) {
+		int i;
+		int k = 0;
+
+		scan_division_num = (ch_num / max_allow_ch) + ((ch_num % max_allow_ch) ? 1 : 0);
+		token = (token + 1) % scan_division_num;
+
+		if (0)
+			RTW_INFO("scan_division_num:%u, token:%u\n", scan_division_num, token);
+
+		for (i = 0; i < ch_num; i++) {
+			if (ch[i].hw_value && (i % scan_division_num) == token
+			   ) {
+				if (i != k)
+					_rtw_memcpy(&ch[k], &ch[i], sizeof(struct rtw_ieee80211_channel));
+				k++;
+			}
+		}
+
+		_rtw_memset(&ch[k], 0, sizeof(struct rtw_ieee80211_channel));
+
+		ret_num = k;
+		mlmeext->last_scan_time = rtw_get_current_time();
+	}
+
+exit:
+	return ret_num;
+}
+
+static int rtw_scan_ch_decision(_adapter *padapter, struct rtw_ieee80211_channel *out,
+		u32 out_num, struct rtw_ieee80211_channel *in, u32 in_num)
+{
+	int i, j;
+	int scan_ch_num = 0;
+	int set_idx;
+	u8 chan;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+
+	/* clear first */
+	_rtw_memset(out, 0, sizeof(struct rtw_ieee80211_channel) * out_num);
+
+	/* acquire channels from in */
+	j = 0;
+	for (i = 0; i < in_num; i++) {
+
+		if (0)
+			RTW_INFO(FUNC_ADPT_FMT" "CHAN_FMT"\n", FUNC_ADPT_ARG(padapter), CHAN_ARG(&in[i]));
+
+		if (!in[i].hw_value || (in[i].flags & RTW_IEEE80211_CHAN_DISABLED))
+			continue;
+		if (rtw_mlme_band_check(padapter, in[i].hw_value) == _FALSE)
+			continue;
+
+		set_idx = rtw_chset_search_ch(pmlmeext->channel_set, in[i].hw_value);
+		if (set_idx >= 0) {
+			if (j >= out_num) {
+				RTW_PRINT(FUNC_ADPT_FMT" out_num:%u not enough\n",
+					  FUNC_ADPT_ARG(padapter), out_num);
+				break;
+			}
+
+			_rtw_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++) {
+			chan = pmlmeext->channel_set[i].ChannelNum;
+			if (rtw_mlme_band_check(padapter, chan) == _TRUE) {
+				if (rtw_mlme_ignore_chan(padapter, chan) == _TRUE)
+					continue;
+
+				if (0)
+					RTW_INFO(FUNC_ADPT_FMT" ch:%u\n", FUNC_ADPT_ARG(padapter), chan);
+
+				if (j >= out_num) {
+					RTW_PRINT(FUNC_ADPT_FMT" out_num:%u not enough\n",
+						FUNC_ADPT_ARG(padapter), out_num);
+					break;
+				}
+
+				out[j].hw_value = chan;
+
+				if (pmlmeext->channel_set[i].ScanType == SCAN_PASSIVE)
+					out[j].flags |= RTW_IEEE80211_CHAN_PASSIVE_SCAN;
+
+				j++;
+			}
+		}
+	}
+
+	/* scan_sparse */
+	j = rtw_scan_sparse(padapter, out, j);
+
+	return j;
+}
+
+static void sitesurvey_res_reset(_adapter *adapter, struct sitesurvey_parm *parm)
+{
+	struct ss_res *ss = &adapter->mlmeextpriv.sitesurvey_res;
+	int i;
+
+	ss->bss_cnt = 0;
+	ss->channel_idx = 0;
+	ss->igi_scan = 0;
+	ss->igi_before_scan = 0;
+
+	ss->ssid_num = 0;
+	for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) {
+		if (parm->ssid[i].SsidLength) {
+			_rtw_memcpy(ss->ssid[i].Ssid, parm->ssid[i].Ssid, IW_ESSID_MAX_SIZE);
+			ss->ssid[i].SsidLength = parm->ssid[i].SsidLength;
+			ss->ssid_num++;
+		} else
+			ss->ssid[i].SsidLength = 0;
+	}
+
+	ss->ch_num = rtw_scan_ch_decision(adapter
+					  , ss->ch, RTW_CHANNEL_SCAN_AMOUNT
+					  , parm->ch, parm->ch_num
+					 );
+
+
+	ss->scan_mode = parm->scan_mode;
+}
+
+static u8 sitesurvey_pick_ch_behavior(_adapter *padapter, u8 *ch, RT_SCAN_TYPE *type)
+{
+	u8 next_state;
+	u8 scan_ch = 0;
+	RT_SCAN_TYPE scan_type = SCAN_PASSIVE;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+	struct ss_res *ss = &pmlmeext->sitesurvey_res;
+
+	struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+	/* handle scan abort request */
+	scan_abort_hdl(padapter);
+
+	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)
+			scan_ch = pwdinfo->rx_invitereq_info.operation_ch[ss->channel_idx];
+		else
+			scan_ch = pwdinfo->p2p_info.operation_ch[ss->channel_idx];
+		scan_type = 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;
+
+		scan_ch = pwdinfo->social_chan[ss->channel_idx];
+		ch_set_idx = rtw_chset_search_ch(pmlmeext->channel_set, scan_ch);
+		if (ch_set_idx >= 0)
+			scan_type = pmlmeext->channel_set[ch_set_idx].ScanType;
+		else
+			scan_type = SCAN_ACTIVE;
+	} else
+	{
+		struct rtw_ieee80211_channel *ch;
+
+
+		if (ss->channel_idx < ss->ch_num) {
+			ch = &ss->ch[ss->channel_idx];
+			scan_ch = ch->hw_value;
+			scan_type = (ch->flags & RTW_IEEE80211_CHAN_PASSIVE_SCAN) ? SCAN_PASSIVE : SCAN_ACTIVE;
+		}
+	}
+
+	if (scan_ch != 0) {
+		next_state = SCAN_PROCESS;
+	} else if (rtw_p2p_findphase_ex_is_needed(pwdinfo)) {
+		/* go p2p listen */
+		next_state = SCAN_TO_P2P_LISTEN;
+
+	} else {
+		next_state = SCAN_COMPLETE;
+
+	}
+
+
+
+	if (ch)
+		*ch = scan_ch;
+	if (type)
+		*type = scan_type;
+
+	return next_state;
+}
+
+void site_survey(_adapter *padapter, u8 survey_channel, RT_SCAN_TYPE ScanType)
+{
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct ss_res *ss = &pmlmeext->sitesurvey_res;
+	u8 ssid_scan = 0;
+
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	if (survey_channel != 0) {
+		set_channel_bwmode(padapter, survey_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
+
+
+		if (ScanType == SCAN_ACTIVE) {
+			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
+			{
+				if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) {
+					/* IOT issue, When wifi_spec is not set, send one probe req without WPS IE. */
+					if (padapter->registrypriv.wifi_spec)
+						issue_probereq(padapter, NULL, NULL);
+					else
+						issue_probereq_ex(padapter, NULL, NULL, 0, 0, 0, 0);
+					issue_probereq(padapter, NULL, NULL);
+				}
+
+				ssid_scan = 1;
+			}
+		}
+
+		if (ssid_scan) {
+			int i;
+
+			for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) {
+				if (pmlmeext->sitesurvey_res.ssid[i].SsidLength) {
+					/* IOT issue, When wifi_spec is not set, send one probe req without WPS IE. */
+					if (padapter->registrypriv.wifi_spec)
+						issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL);
+					else
+						issue_probereq_ex(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL, 0, 0, 0, 0);
+					issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL);
+				}
+			}
+		}
+	} else {
+		/* channel number is 0 or this channel is not valid. */
+		rtw_warn_on(1);
+	}
+
+	return;
+}
+
+void survey_done_set_ch_bw(_adapter *padapter)
+{
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	u8 cur_channel = 0;
+	u8 cur_bwmode;
+	u8 cur_ch_offset;
+
+	if (rtw_mi_get_ch_setting_union(padapter, &cur_channel, &cur_bwmode, &cur_ch_offset) != 0) {
+		if (0)
+			RTW_INFO(FUNC_ADPT_FMT" back to linked/linking union - ch:%u, bw:%u, offset:%u\n",
+				FUNC_ADPT_ARG(padapter), cur_channel, cur_bwmode, cur_ch_offset);
+	} else {
+		struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+		_adapter *iface;
+		int i;
+
+		for (i = 0; i < dvobj->iface_nums; i++) {
+			iface = dvobj->padapters[i];
+			if (!iface)
+				continue;
+
+
+			if (rtw_p2p_chk_state(&iface->wdinfo, P2P_STATE_LISTEN)) {
+				cur_channel = iface->wdinfo.listen_channel;
+				cur_bwmode = CHANNEL_WIDTH_20;
+				cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+				if (0)
+					RTW_INFO(FUNC_ADPT_FMT" back to "ADPT_FMT"'s listen ch - ch:%u, bw:%u, offset:%u\n",
+						FUNC_ADPT_ARG(padapter), ADPT_ARG(iface), cur_channel, cur_bwmode, cur_ch_offset);
+				break;
+			}
+		}
+
+		if (cur_channel == 0) {
+			cur_channel = pmlmeext->cur_channel;
+			cur_bwmode = pmlmeext->cur_bwmode;
+			cur_ch_offset = pmlmeext->cur_ch_offset;
+			if (0)
+				RTW_INFO(FUNC_ADPT_FMT" back to ch:%u, bw:%u, offset:%u\n",
+					FUNC_ADPT_ARG(padapter), cur_channel, cur_bwmode, cur_ch_offset);
+		}
+	}
+	set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode);
+}
+
+/**
+ * sitesurvey_ps_annc - check and doing ps announcement for all the adapters of given @dvobj
+ * @padapter
+ * @ps: power saving or not
+ *
+ * Returns: 0: no ps announcement is doing. 1: ps announcement is doing
+ */
+
+u8 sitesurvey_ps_annc(_adapter *padapter, bool ps)
+{
+	u8 ps_anc = 0;
+
+	if (rtw_mi_issue_nulldata(padapter, NULL, ps, 3, 500))
+		ps_anc = 1;
+	return ps_anc;
+}
+
+void sitesurvey_set_igi(_adapter *adapter)
+{
+	struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+	struct ss_res *ss = &mlmeext->sitesurvey_res;
+	u8 igi;
+	struct wifidirect_info *pwdinfo = &adapter->wdinfo;
+
+	switch (mlmeext_scan_state(mlmeext)) {
+	case SCAN_ENTER:
+		if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+			igi = 0x28;
+		else
+			igi = 0x1e;
+
+		/* record IGI status */
+		ss->igi_scan = igi;
+		rtw_hal_get_odm_var(adapter, HAL_ODM_INITIAL_GAIN, &ss->igi_before_scan, NULL);
+
+		/* disable DIG and set IGI for scan */
+		rtw_hal_set_odm_var(adapter, HAL_ODM_INITIAL_GAIN, &igi, _FALSE);
+		break;
+	case SCAN_COMPLETE:
+	case SCAN_TO_P2P_LISTEN:
+		/* enable DIG and restore IGI */
+		igi = 0xff;
+		rtw_hal_set_odm_var(adapter, HAL_ODM_INITIAL_GAIN, &igi, _FALSE);
+		break;
+	default:
+		rtw_warn_on(1);
+		break;
+	}
+}
+void sitesurvey_set_msr(_adapter *adapter, bool enter)
+{
+	u8 network_type;
+	struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if (enter) {
+		/* set MSR to no link state */
+		network_type = _HW_STATE_NOLINK_;
+	} else {
+		network_type = pmlmeinfo->state & 0x3;
+	}
+	Set_MSR(adapter, network_type);
+}
+u8 sitesurvey_cmd_hdl(_adapter *padapter, u8 *pbuf)
+{
+	struct sitesurvey_parm	*pparm = (struct sitesurvey_parm *)pbuf;
+	struct dvobj_priv *dvobj = padapter->dvobj;
+	struct debug_priv *pdbgpriv = &dvobj->drv_dbg;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct ss_res *ss = &pmlmeext->sitesurvey_res;
+	u8 val8;
+
+	struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+
+	/* increase channel idx */
+	if (mlmeext_chk_scan_state(pmlmeext, SCAN_PROCESS))
+		ss->channel_idx++;
+
+	/* update scan state to next state (assigned by previous cmd hdl) */
+	if (mlmeext_scan_state(pmlmeext) != mlmeext_scan_next_state(pmlmeext))
+		mlmeext_set_scan_state(pmlmeext, mlmeext_scan_next_state(pmlmeext));
+
+operation_by_state:
+	switch (mlmeext_scan_state(pmlmeext)) {
+
+	case SCAN_DISABLE:
+		/*
+		* SW parameter initialization
+		*/
+
+		sitesurvey_res_reset(padapter, pparm);
+		mlmeext_set_scan_state(pmlmeext, SCAN_START);
+		goto operation_by_state;
+
+	case SCAN_START:
+		/*
+		* prepare to leave operating channel
+		*/
+
+		/* apply rx ampdu setting */
+		if (ss->rx_ampdu_accept != RX_AMPDU_ACCEPT_INVALID
+			|| ss->rx_ampdu_size != RX_AMPDU_SIZE_INVALID)
+			rtw_rx_ampdu_apply(padapter);
+
+		/* clear HW TX queue before scan */
+		rtw_hal_set_hwreg(padapter, HW_VAR_CHECK_TXBUF, 0);
+
+		/* power save state announcement */
+		if (sitesurvey_ps_annc(padapter, 1)) {
+			mlmeext_set_scan_state(pmlmeext, SCAN_PS_ANNC_WAIT);
+			mlmeext_set_scan_next_state(pmlmeext, SCAN_ENTER);
+			set_survey_timer(pmlmeext, 50); /* delay 50ms to protect nulldata(1) */
+		} else {
+			mlmeext_set_scan_state(pmlmeext, SCAN_ENTER);
+			goto operation_by_state;
+		}
+
+		break;
+
+	case SCAN_ENTER:
+		/*
+		* HW register and DM setting for enter scan
+		*/
+
+		rtw_phydm_ability_backup(padapter);
+
+		sitesurvey_set_igi(padapter);
+
+		/* config dynamic functions for off channel */
+		rtw_phydm_func_for_offchannel(padapter);
+		/* set MSR to no link state */
+		sitesurvey_set_msr(padapter, _TRUE);
+
+		val8 = 1; /* under site survey */
+		rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+
+		mlmeext_set_scan_state(pmlmeext, SCAN_PROCESS);
+		goto operation_by_state;
+
+	case SCAN_PROCESS: {
+		u8 scan_ch;
+		RT_SCAN_TYPE scan_type;
+		u8 next_state;
+		u32 scan_ms;
+
+
+		next_state = sitesurvey_pick_ch_behavior(padapter, &scan_ch, &scan_type);
+		if (next_state != SCAN_PROCESS) {
+
+			mlmeext_set_scan_state(pmlmeext, next_state);
+			goto operation_by_state;
+		}
+
+		/* still SCAN_PROCESS state */
+		if (0)
+			RTW_INFO(FUNC_ADPT_FMT" %s ch:%u (cnt:%u,idx:%d) at %dms, %c%c%c\n"
+				 , FUNC_ADPT_ARG(padapter)
+				 , mlmeext_scan_state_str(pmlmeext)
+				 , scan_ch
+				, pwdinfo->find_phase_state_exchange_cnt, ss->channel_idx
+				, rtw_get_passing_time_ms(padapter->mlmepriv.scan_start_time)
+				, scan_type ? 'A' : 'P', ss->scan_mode ? 'A' : 'P'
+				 , ss->ssid[0].SsidLength ? 'S' : ' '
+				);
+
+
+		site_survey(padapter, scan_ch, scan_type);
+
+		scan_ms = ss->scan_ch_ms;
+
+
+
+		set_survey_timer(pmlmeext, scan_ms);
+		break;
+	}
+
+
+
+	case SCAN_TO_P2P_LISTEN:
+		/*
+		* 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, CHANNEL_WIDTH_20);
+		rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_LISTEN);
+
+		/* turn on phy-dynamic functions */
+		rtw_phydm_ability_restore(padapter);
+
+		sitesurvey_set_igi(padapter);
+
+		mlmeext_set_scan_state(pmlmeext, SCAN_P2P_LISTEN);
+		_set_timer(&pwdinfo->find_phase_timer, (u32)((u32)pwdinfo->listen_dwell * 100));
+		break;
+
+	case SCAN_P2P_LISTEN:
+		mlmeext_set_scan_state(pmlmeext, SCAN_PROCESS);
+		ss->channel_idx = 0;
+		goto operation_by_state;
+
+	case SCAN_COMPLETE:
+		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);
+
+		/* switch channel */
+		survey_done_set_ch_bw(padapter);
+
+		sitesurvey_set_msr(padapter, _FALSE);
+
+		val8 = 0; /* survey done */
+		rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+
+		/* turn on phy-dynamic functions */
+		rtw_phydm_ability_restore(padapter);
+
+		sitesurvey_set_igi(padapter);
+
+			sitesurvey_ps_annc(padapter, 0);
+
+		/* apply rx ampdu setting */
+		rtw_rx_ampdu_apply(padapter);
+
+		mlmeext_set_scan_state(pmlmeext, SCAN_DISABLE);
+
+		report_surveydone_event(padapter);
+
+		issue_action_BSSCoexistPacket(padapter);
+		issue_action_BSSCoexistPacket(padapter);
+		issue_action_BSSCoexistPacket(padapter);
+	}
+
+	return H2C_SUCCESS;
+}
+
+u8 setauth_hdl(_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;
+}
+
+/*
+SEC CAM Entry format (32 bytes)
+DW0 - MAC_ADDR[15:0] | Valid[15] | MFB[14:8] | RSVD[7]  | GK[6] | MIC_KEY[5] | SEC_TYPE[4:2] | KID[1:0]
+DW0 - MAC_ADDR[15:0] | Valid[15] |RSVD[14:9] | RPT_MODE[8] | SPP_MODE[7]  | GK[6] | MIC_KEY[5] | SEC_TYPE[4:2] | KID[1:0] (92E/8812A/8814A)
+DW1 - MAC_ADDR[47:16]
+DW2 - KEY[31:0]
+DW3 - KEY[63:32]
+DW4 - KEY[95:64]
+DW5 - KEY[127:96]
+DW6 - RSVD
+DW7 - RSVD
+*/
+
+/*Set WEP key or Group Key*/
+u8 setkey_hdl(_adapter *padapter, u8 *pbuf)
+{
+	u16	ctrl = 0;
+	s16 cam_id = 0;
+	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_addr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+	u8 *addr;
+	bool used = _FALSE;
+
+	/* main tx key for wep. */
+	if (pparm->set_tx)
+		pmlmeinfo->key_index = pparm->keyid;
+
+	cam_id = rtw_camid_alloc(padapter, NULL, pparm->keyid, &used);
+
+	if (cam_id < 0)
+		goto enable_mc;
+
+	if (cam_id >= 0 && cam_id <= 3)
+		addr = null_addr;
+	else
+	{
+		if (((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE))
+			/* for AP mode ,we will force sec cam entry_id so hw dont search cam when tx*/
+			addr = adapter_mac_addr(padapter);
+		else
+			/* not default key, searched by A2 */
+			addr = get_bssid(&padapter->mlmepriv);
+	}
+
+	/* cam entry searched is pairwise key */
+	if (used == _TRUE && rtw_camid_is_gk(padapter, cam_id) == _FALSE) {
+		s16 camid_clr;
+
+		RTW_PRINT(FUNC_ADPT_FMT" group key with "MAC_FMT" id:%u the same key id as pairwise key\n"
+			, FUNC_ADPT_ARG(padapter), MAC_ARG(addr), pparm->keyid);
+
+		/* HW has problem to distinguish this group key with existing pairwise key, stop HW enc and dec for BMC */
+		rtw_camctl_set_flags(padapter, SEC_STATUS_STA_PK_GK_CONFLICT_DIS_BMC_SEARCH);
+		rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, NULL);
+
+		/* clear group key */
+		while ((camid_clr = rtw_camid_search(padapter, addr, -1, 1)) >= 0) {
+			RTW_PRINT("clear group key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(addr), camid_clr);
+			clear_cam_entry(padapter, camid_clr);
+			rtw_camid_free(padapter, camid_clr);
+		}
+
+		goto enable_mc;
+	}
+
+	ctrl = BIT(15) | BIT(6) | ((pparm->algorithm) << 2) | pparm->keyid;
+
+	RTW_PRINT("set group key camid:%d, addr:"MAC_FMT", kid:%d, type:%s\n"
+		, cam_id, MAC_ARG(addr), pparm->keyid, security_type_str(pparm->algorithm));
+
+	write_cam(padapter, cam_id, ctrl, addr, pparm->key);
+
+	/* if ((cam_id > 3) && (((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)))*/
+
+	if (cam_id >= 0 && cam_id <= 3)
+		rtw_hal_set_hwreg(padapter, HW_VAR_SEC_DK_CFG, (u8 *)_TRUE);
+
+	/* 8814au should set both broadcast and unicast CAM entry for WEP key in STA mode */
+	if (is_wep_enc(pparm->algorithm) && check_mlmeinfo_state(pmlmeext, WIFI_FW_STATION_STATE) &&
+	    _rtw_camctl_chk_cap(padapter, SEC_CAP_CHK_BMC)) {
+		struct set_stakey_parm	sta_pparm;
+
+		sta_pparm.algorithm = pparm->algorithm;
+		sta_pparm.keyid = pparm->keyid;
+		_rtw_memcpy(sta_pparm.key, pparm->key, 16);
+		_rtw_memcpy(sta_pparm.addr, get_bssid(&padapter->mlmepriv), ETH_ALEN);
+		set_stakey_hdl(padapter, (u8 *)&sta_pparm);
+	}
+
+enable_mc:
+	/* allow multicast packets to driver */
+	rtw_hal_set_hwreg(padapter, HW_VAR_ON_RCR_AM, null_addr);
+
+	return H2C_SUCCESS;
+}
+
+void rtw_ap_wep_pk_setting(_adapter *adapter, struct sta_info *psta)
+{
+	struct security_priv *psecuritypriv = &(adapter->securitypriv);
+	struct set_stakey_parm	sta_pparm;
+	sint keyid;
+
+	if (!is_wep_enc(psecuritypriv->dot11PrivacyAlgrthm))
+		return;
+
+	for (keyid = 0; keyid < 4; keyid++) {
+		if ((psecuritypriv->key_mask & BIT(keyid)) && (keyid == psecuritypriv->dot11PrivacyKeyIndex)) {
+			sta_pparm.algorithm = psecuritypriv->dot11PrivacyAlgrthm;
+			sta_pparm.keyid = keyid;
+			_rtw_memcpy(sta_pparm.key, &(psecuritypriv->dot11DefKey[keyid].skey[0]), 16);
+			_rtw_memcpy(sta_pparm.addr, psta->hwaddr, ETH_ALEN);
+
+			RTW_PRINT(FUNC_ADPT_FMT"set WEP - PK with "MAC_FMT" keyid:%u\n"
+				, FUNC_ADPT_ARG(adapter), MAC_ARG(psta->hwaddr), keyid);
+
+			set_stakey_hdl(adapter, (u8 *)&sta_pparm);
+		}
+	}
+}
+
+u8 set_stakey_hdl(_adapter *padapter, u8 *pbuf)
+{
+	u16 ctrl = 0;
+	s16 cam_id = 0;
+	bool used;
+	u8 kid = 0;
+	u8 ret = H2C_SUCCESS;
+	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;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct sta_info *psta;
+
+	if (pparm->algorithm == _NO_PRIVACY_)
+		goto write_to_cam;
+
+	psta = rtw_get_stainfo(pstapriv, pparm->addr);
+	if (!psta) {
+		RTW_PRINT("%s sta:"MAC_FMT" not found\n", __func__, MAC_ARG(pparm->addr));
+		ret = H2C_REJECTED;
+		goto exit;
+	}
+
+	pmlmeinfo->enc_algo = pparm->algorithm;
+	if (is_wep_enc(pparm->algorithm))
+		kid = pparm->keyid;
+	cam_id = rtw_camid_alloc(padapter, psta, kid, &used);
+	if (cam_id < 0)
+		goto exit;
+
+	/* cam entry searched is group key */
+	if (used == _TRUE && rtw_camid_is_gk(padapter, cam_id) == _TRUE) {
+		s16 camid_clr;
+
+		RTW_PRINT(FUNC_ADPT_FMT" pairwise key with "MAC_FMT" id:%u the same key id as group key\n"
+			, FUNC_ADPT_ARG(padapter), MAC_ARG(pparm->addr), pparm->keyid);
+
+		/* HW has problem to distinguish this pairwise key with existing group key, stop HW enc and dec for BMC */
+		rtw_camctl_set_flags(padapter, SEC_STATUS_STA_PK_GK_CONFLICT_DIS_BMC_SEARCH);
+		rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, NULL);
+
+		/* clear group key */
+		while ((camid_clr = rtw_camid_search(padapter, pparm->addr, -1, 1)) >= 0) {
+			RTW_PRINT("clear group key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(pparm->addr), camid_clr);
+			clear_cam_entry(padapter, camid_clr);
+			rtw_camid_free(padapter, camid_clr);
+		}
+	}
+
+write_to_cam:
+	if (pparm->algorithm == _NO_PRIVACY_) {
+		while ((cam_id = rtw_camid_search(padapter, pparm->addr, -1, -1)) >= 0) {
+			RTW_PRINT("clear key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(pparm->addr), cam_id);
+			clear_cam_entry(padapter, cam_id);
+			rtw_camid_free(padapter, cam_id);
+		}
+	} else {
+		RTW_PRINT("set pairwise key camid:%d, addr:"MAC_FMT", kid:%d, type:%s\n",
+			cam_id, MAC_ARG(pparm->addr), pparm->keyid, security_type_str(pparm->algorithm));
+		ctrl = BIT(15) | ((pparm->algorithm) << 2) | pparm->keyid;
+		write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key);
+	}
+	ret = H2C_SUCCESS_RSP;
+
+exit:
+	return ret;
+}
+
+u8 add_ba_hdl(_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)) {
+		/* pmlmeinfo->ADDBA_retry_count = 0; */
+		/* pmlmeinfo->candidate_tid_bitmap |= (0x1 << pparm->tid);		 */
+		/* psta->htpriv.candidate_tid_bitmap |= BIT(pparm->tid); */
+		issue_addba_req(padapter, pparm->addr, (u8)pparm->tid);
+		_set_timer(&psta->addba_retry_timer, ADDBA_TO);
+	}
+	else
+		psta->htpriv.candidate_tid_bitmap &= ~BIT(pparm->tid);
+	return	H2C_SUCCESS;
+}
+
+u8 add_ba_rsp_hdl(_adapter *padapter, unsigned char *pbuf)
+{
+	struct addBaRsp_parm *pparm = (struct addBaRsp_parm *)pbuf;
+	u8 ret = _TRUE, i = 0, try_cnt = 3, wait_ms = 50;
+	struct recv_reorder_ctrl *preorder_ctrl;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct sta_info *psta;
+
+	psta = rtw_get_stainfo(pstapriv, pparm->addr);
+	if (!psta)
+		goto exit;
+
+	preorder_ctrl = &psta->recvreorder_ctrl[pparm->tid];
+	ret = issue_addba_rsp_wait_ack(padapter, pparm->addr, pparm->tid, pparm->status, pparm->size, 3, 50);
+
+#ifdef CONFIG_UPDATE_INDICATE_SEQ_WHILE_PROCESS_ADDBA_REQ
+	/* status = 0 means accept this addba req, so update indicate seq = start_seq under this compile flag */
+	if (pparm->status == 0) {
+		preorder_ctrl->indicate_seq = pparm->start_seq;
+	}
+#else
+	preorder_ctrl->indicate_seq = 0xffff;
+#endif
+
+	/*
+	  * status = 0 means accept this addba req
+	  * status = 37 means reject this addba req
+	  */
+	if (pparm->status == 0) {
+		preorder_ctrl->enable = _TRUE;
+		preorder_ctrl->ampdu_size = pparm->size;
+	} else if (pparm->status == 37)
+		preorder_ctrl->enable = _FALSE;
+
+exit:
+	return H2C_SUCCESS;
+}
+
+u8 chk_bmc_sleepq_cmd(_adapter *padapter)
+{
+	struct cmd_obj *ph2c;
+	struct cmd_priv *pcmdpriv = &(padapter->cmdpriv);
+	u8 res = _SUCCESS;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_parm_rsp(ph2c, GEN_CMD_CODE(_ChkBMCSleepq));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+	return res;
+}
+
+u8 set_tx_beacon_cmd(_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) {
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct	cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	_rtw_memcpy(&(ptxBeacon_parm->network), &(pmlmeinfo->network), sizeof(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(_adapter *padapter, unsigned char *pbuf)
+{
+	u8 evt_code, evt_seq;
+	u16 evt_sz;
+	uint	*peventbuf;
+	void (*event_callback)(_adapter *dev, u8 *pbuf);
+	struct evt_priv *pevt_priv = &(padapter->evtpriv);
+
+	if (pbuf == NULL)
+		goto _abort_event_;
+
+	peventbuf = (uint *)pbuf;
+	evt_sz = (u16)(*peventbuf & 0xffff);
+	evt_seq = (u8)((*peventbuf >> 24) & 0x7f);
+	evt_code = (u8)((*peventbuf >> 16) & 0xff);
+
+#ifdef CHECK_EVENT_SEQ
+	/* checking event sequence...		 */
+	if (evt_seq != (ATOMIC_READ(&pevt_priv->event_seq) & 0x7f)) {
+
+		pevt_priv->event_seq = (evt_seq + 1) & 0x7f;
+
+		goto _abort_event_;
+	}
+#endif
+
+	/* checking if event code is valid */
+	if (evt_code >= MAX_C2HEVT) {
+		goto _abort_event_;
+	}
+
+	/* checking if event size match the event parm size	 */
+	if ((wlanevents[evt_code].parmsize != 0) &&
+	    (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(_adapter *padapter, unsigned char *pbuf)
+{
+	if (!pbuf)
+		return H2C_PARAMETERS_ERROR;
+
+	return H2C_SUCCESS;
+}
+
+u8 chk_bmc_sleepq_hdl(_adapter *padapter, unsigned char *pbuf)
+{
+	_irqL irqL;
+	struct sta_info *psta_bmc;
+	_list	*xmitframe_plist, *xmitframe_phead;
+	struct xmit_frame *pxmitframe = NULL;
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+	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)) {
+		/* _enter_critical_bh(&psta_bmc->sleep_q.lock, &irqL); */
+		_enter_critical_bh(&pxmitpriv->lock, &irqL);
+
+		xmitframe_phead = get_list_head(&psta_bmc->sleep_q);
+		xmitframe_plist = get_next(xmitframe_phead);
+
+		while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) {
+			pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+
+			xmitframe_plist = get_next(xmitframe_plist);
+
+			rtw_list_delete(&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;
+
+			if (xmitframe_hiq_filter(pxmitframe) == _TRUE)
+				pxmitframe->attrib.qsel = QSLT_HIGH;/* HIQ */
+
+			rtw_hal_xmitframe_enqueue(padapter, pxmitframe);
+		}
+
+		/* _exit_critical_bh(&psta_bmc->sleep_q.lock, &irqL); */
+		_exit_critical_bh(&pxmitpriv->lock, &irqL);
+
+		if (rtw_get_intf_type(padapter) != RTW_PCIE) {
+			/* check hi queue and bmc_sleepq */
+			rtw_chk_hi_queue_cmd(padapter);
+		}
+	}
+
+	return H2C_SUCCESS;
+}
+
+u8 tx_beacon_hdl(_adapter *padapter, unsigned char *pbuf)
+{
+
+
+	if (send_beacon(padapter) == _FAIL) {
+		RTW_INFO("issue_beacon, fail!\n");
+		return H2C_PARAMETERS_ERROR;
+	}
+
+	/* tx bc/mc frames after update TIM */
+	chk_bmc_sleepq_hdl(padapter, NULL);
+
+	return H2C_SUCCESS;
+}
+
+/*
+* according to channel
+* add/remove WLAN_BSSID_EX.IEs's ERP ie
+* set WLAN_BSSID_EX.SupportedRates
+* update WLAN_BSSID_EX.IEs's Supported Rate and Extended Supported Rate ie
+*/
+void change_band_update_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 ch)
+{
+	u8	network_type, rate_len, total_rate_len, remainder_rate_len;
+	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8	erpinfo = 0x4;
+
+	if (ch >= 36) {
+		network_type = WIRELESS_11A;
+		total_rate_len = IEEE80211_NUM_OFDM_RATESLEN;
+		rtw_remove_bcn_ie(padapter, pnetwork, _ERPINFO_IE_);
+	} else {
+		network_type = WIRELESS_11BG;
+		total_rate_len = IEEE80211_CCK_RATE_LEN + IEEE80211_NUM_OFDM_RATESLEN;
+		rtw_add_bcn_ie(padapter, pnetwork, _ERPINFO_IE_, &erpinfo, 1);
+	}
+
+	rtw_set_supported_rate(pnetwork->SupportedRates, network_type);
+
+	UpdateBrateTbl(padapter, pnetwork->SupportedRates);
+
+	if (total_rate_len > 8) {
+		rate_len = 8;
+		remainder_rate_len = total_rate_len - 8;
+	} else {
+		rate_len = total_rate_len;
+		remainder_rate_len = 0;
+	}
+
+	rtw_add_bcn_ie(padapter, pnetwork, _SUPPORTEDRATES_IE_, pnetwork->SupportedRates, rate_len);
+
+	if (remainder_rate_len)
+		rtw_add_bcn_ie(padapter, pnetwork, _EXT_SUPPORTEDRATES_IE_, (pnetwork->SupportedRates + 8), remainder_rate_len);
+	else
+		rtw_remove_bcn_ie(padapter, pnetwork, _EXT_SUPPORTEDRATES_IE_);
+
+	pnetwork->Length = get_WLAN_BSSID_EX_sz(pnetwork);
+}
+
+void rtw_join_done_chk_ch(_adapter *adapter, int join_res)
+{
+#define DUMP_ADAPTERS_STATUS 0
+
+	struct dvobj_priv *dvobj;
+	_adapter *iface;
+	struct mlme_priv *mlme;
+	struct mlme_ext_priv *mlmeext;
+	u8 u_ch, u_offset, u_bw;
+	int i;
+
+	dvobj = adapter_to_dvobj(adapter);
+
+	if (DUMP_ADAPTERS_STATUS) {
+		RTW_INFO(FUNC_ADPT_FMT" enter\n", FUNC_ADPT_ARG(adapter));
+		dump_adapters_status(RTW_DBGDUMP , dvobj);
+	}
+
+	if (join_res >= 0) {
+
+		if (rtw_mi_get_ch_setting_union(adapter, &u_ch, &u_bw, &u_offset) <= 0) {
+			dump_adapters_status(RTW_DBGDUMP , dvobj);
+			rtw_warn_on(1);
+		}
+
+		for (i = 0; i < dvobj->iface_nums; i++) {
+			iface = dvobj->padapters[i];
+			mlme = &iface->mlmepriv;
+			mlmeext = &iface->mlmeextpriv;
+
+			if (!iface || iface == adapter)
+				continue;
+
+			if (check_fwstate(mlme, WIFI_AP_STATE)
+				&& check_fwstate(mlme, WIFI_ASOC_STATE)
+			) {
+				bool is_grouped = rtw_is_chbw_grouped(u_ch, u_bw, u_offset
+					, mlmeext->cur_channel, mlmeext->cur_bwmode, mlmeext->cur_ch_offset);
+
+				if (is_grouped == _FALSE) {
+					/* handle AP which need to switch ch setting */
+
+					/* restore original bw, adjust bw by registry setting on target ch */
+					mlmeext->cur_bwmode = mlme->ori_bw;
+					mlmeext->cur_channel = u_ch;
+					rtw_adjust_chbw(iface
+						, mlmeext->cur_channel, &mlmeext->cur_bwmode, &mlmeext->cur_ch_offset);
+
+					rtw_sync_chbw(&mlmeext->cur_channel, &mlmeext->cur_bwmode, &mlmeext->cur_ch_offset
+						, &u_ch, &u_bw, &u_offset);
+
+					rtw_ap_update_bss_chbw(iface, &(mlmeext->mlmext_info.network)
+						, mlmeext->cur_channel, mlmeext->cur_bwmode, mlmeext->cur_ch_offset);
+
+					_rtw_memcpy(&(mlme->cur_network.network), &(mlmeext->mlmext_info.network), sizeof(WLAN_BSSID_EX));
+
+					rtw_start_bss_hdl_after_chbw_decided(iface);
+				}
+
+				clr_fwstate(mlme, WIFI_OP_CH_SWITCHING);
+				update_beacon(iface, 0, NULL, _TRUE);
+			}
+		}
+
+	} else {
+		for (i = 0; i < dvobj->iface_nums; i++) {
+			iface = dvobj->padapters[i];
+			mlme = &iface->mlmepriv;
+			mlmeext = &iface->mlmeextpriv;
+
+			if (!iface || iface == adapter)
+				continue;
+
+			if (check_fwstate(mlme, WIFI_AP_STATE)
+				&& check_fwstate(mlme, WIFI_ASOC_STATE)
+			) {
+				clr_fwstate(mlme, WIFI_OP_CH_SWITCHING);
+				update_beacon(iface, 0, NULL, _TRUE);
+			}
+		}
+	}
+
+	if (rtw_mi_get_ch_setting_union(adapter, &u_ch, &u_bw, &u_offset)) {
+		set_channel_bwmode(adapter, u_ch, u_offset, u_bw);
+		rtw_mi_update_union_chan_inf(adapter, u_ch, u_offset, u_bw);
+	}
+
+	if (DUMP_ADAPTERS_STATUS) {
+		RTW_INFO(FUNC_ADPT_FMT" exit\n", FUNC_ADPT_ARG(adapter));
+		dump_adapters_status(RTW_DBGDUMP , dvobj);
+	}
+}
+
+int rtw_chk_start_clnt_join(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset)
+{
+	bool chbw_allow = _TRUE;
+	bool connect_allow = _TRUE;
+	struct mlme_ext_priv	*pmlmeext = &adapter->mlmeextpriv;
+	u8 cur_ch, cur_bw, cur_ch_offset;
+	u8 u_ch, u_offset, u_bw;
+
+	u_ch = cur_ch = pmlmeext->cur_channel;
+	u_bw = cur_bw = pmlmeext->cur_bwmode;
+	u_offset = cur_ch_offset = pmlmeext->cur_ch_offset;
+
+	if (!ch || !bw || !offset) {
+		connect_allow = _FALSE;
+		rtw_warn_on(1);
+		goto exit;
+	}
+
+	if (cur_ch == 0) {
+		connect_allow = _FALSE;
+		RTW_ERR(FUNC_ADPT_FMT" cur_ch:%u\n"
+			, FUNC_ADPT_ARG(adapter), cur_ch);
+		rtw_warn_on(1);
+		goto exit;
+	}
+	RTW_INFO(FUNC_ADPT_FMT" req: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset);
+
+
+exit:
+
+	if (connect_allow == _TRUE) {
+		RTW_INFO(FUNC_ADPT_FMT" union: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset);
+		*ch = u_ch;
+		*bw = u_bw;
+		*offset = u_offset;
+	}
+
+	return connect_allow == _TRUE ? _SUCCESS : _FAIL;
+}
+
+u8 set_ch_hdl(_adapter *padapter, u8 *pbuf)
+{
+	struct set_ch_parm *set_ch_parm;
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+
+	if (!pbuf)
+		return H2C_PARAMETERS_ERROR;
+
+	set_ch_parm = (struct set_ch_parm *)pbuf;
+
+	RTW_INFO(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(_adapter *padapter, unsigned char *pbuf)
+{
+	struct SetChannelPlan_param *setChannelPlan_param;
+	struct mlme_priv *mlme = &padapter->mlmepriv;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+	if (!pbuf)
+		return H2C_PARAMETERS_ERROR;
+
+	setChannelPlan_param = (struct SetChannelPlan_param *)pbuf;
+
+	if (!rtw_is_channel_plan_valid(setChannelPlan_param->channel_plan))
+		return H2C_PARAMETERS_ERROR;
+
+	mlme->country_ent = setChannelPlan_param->country_ent;
+	mlme->ChannelPlan = setChannelPlan_param->channel_plan;
+
+	pmlmeext->max_chan_nums = init_channel_set(padapter, setChannelPlan_param->channel_plan, pmlmeext->channel_set);
+	init_channel_list(padapter, pmlmeext->channel_set, &pmlmeext->channel_list);
+
+	rtw_hal_set_odm_var(padapter, HAL_ODM_REGULATION, NULL, _TRUE);
+
+
+	return	H2C_SUCCESS;
+}
+
+u8 led_blink_hdl(_adapter *padapter, unsigned char *pbuf)
+{
+	struct LedBlink_param *ledBlink_param;
+
+	if (!pbuf)
+		return H2C_PARAMETERS_ERROR;
+
+	ledBlink_param = (struct LedBlink_param *)pbuf;
+
+
+	return	H2C_SUCCESS;
+}
+
+u8 set_csa_hdl(_adapter *padapter, unsigned char *pbuf)
+{
+	return	H2C_REJECTED;
+
+}
+
+u8 tdls_hdl(_adapter *padapter, unsigned char *pbuf)
+{
+	return H2C_REJECTED;
+
+}
+
+u8 run_in_thread_hdl(_adapter *padapter, u8 *pbuf)
+{
+	struct RunInThread_param *p;
+
+	if (NULL == pbuf)
+		return H2C_PARAMETERS_ERROR;
+	p = (struct RunInThread_param *)pbuf;
+
+	if (p->func)
+		p->func(p->context);
+
+	return H2C_SUCCESS;
+}
+
+u8 rtw_getmacreg_hdl(_adapter *padapter, u8 *pbuf)
+{
+
+	struct readMAC_parm *preadmacparm = NULL;
+	u8 sz = 0;
+	u32	addr = 0;
+	u32	value = 0;
+
+	if (!pbuf)
+		return H2C_PARAMETERS_ERROR;
+
+	preadmacparm = (struct readMAC_parm *) pbuf;
+	sz = preadmacparm->len;
+	addr = preadmacparm->addr;
+	value = 0;
+
+	switch (sz) {
+	case 1:
+		value = rtw_read8(padapter, addr);
+		break;
+	case 2:
+		value = rtw_read16(padapter, addr);
+		break;
+	case 4:
+		value = rtw_read32(padapter, addr);
+		break;
+	default:
+		RTW_INFO("%s: Unknown size\n", __func__);
+		break;
+	}
+	RTW_INFO("%s: addr:0x%02x valeu:0x%02x\n", __func__, addr, value);
+
+	return H2C_SUCCESS;
+}
diff --git a/drivers/staging/rtl8821ce/core/rtw_mp.c b/drivers/staging/rtl8821ce/core/rtw_mp.c
new file mode 100644
index 000000000000..f1926f1243da
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/rtw_mp.c
@@ -0,0 +1,1616 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * 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 <drv_types.h>
+
+#include "../hal/phydm/phydm_precomp.h"
+
+u32 read_bbreg(_adapter *padapter, u32 addr, u32 bitmask)
+{
+	return rtw_hal_read_bbreg(padapter, addr, bitmask);
+}
+
+void write_bbreg(_adapter *padapter, u32 addr, u32 bitmask, u32 val)
+{
+	rtw_hal_write_bbreg(padapter, addr, bitmask, val);
+}
+
+u32 _read_rfreg(PADAPTER padapter, u8 rfpath, u32 addr, u32 bitmask)
+{
+	return rtw_hal_read_rfreg(padapter, rfpath, addr, bitmask);
+}
+
+void _write_rfreg(PADAPTER padapter, u8 rfpath, u32 addr, u32 bitmask, u32 val)
+{
+	rtw_hal_write_rfreg(padapter, rfpath, addr, bitmask, val);
+}
+
+u32 read_rfreg(PADAPTER padapter, u8 rfpath, u32 addr)
+{
+	return _read_rfreg(padapter, rfpath, addr, bRFRegOffsetMask);
+}
+
+void write_rfreg(PADAPTER padapter, u8 rfpath, u32 addr, u32 val)
+{
+	_write_rfreg(padapter, rfpath, addr, bRFRegOffsetMask, val);
+}
+
+static void _init_mp_priv_(struct mp_priv *pmp_priv)
+{
+	WLAN_BSSID_EX *pnetwork;
+
+	_rtw_memset(pmp_priv, 0, sizeof(struct mp_priv));
+
+	pmp_priv->mode = MP_OFF;
+
+	pmp_priv->channel = 1;
+	pmp_priv->bandwidth = CHANNEL_WIDTH_20;
+	pmp_priv->prime_channel_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	pmp_priv->rateidx = 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_bssidpktcount = 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;
+
+	pmp_priv->bSetRxBssid = _FALSE;
+	pmp_priv->bRTWSmbCfg = _FALSE;
+	pmp_priv->bloopback = _FALSE;
+
+	pmp_priv->bloadefusemap = _FALSE;
+
+	pnetwork = &pmp_priv->mp_network.network;
+	_rtw_memcpy(pnetwork->MacAddress, pmp_priv->network_macaddr, ETH_ALEN);
+
+	pnetwork->Ssid.SsidLength = 8;
+	_rtw_memcpy(pnetwork->Ssid.Ssid, "mp_871x", pnetwork->Ssid.SsidLength);
+
+	pmp_priv->tx.payload = 2;
+	pmp_priv->tx.attrib.ht_en = 1;
+
+}
+
+static void mp_init_xmit_attrib(struct mp_tx *pmptx, PADAPTER padapter)
+{
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+
+	struct pkt_attrib *pattrib;
+
+	/* init xmitframe attribute */
+	pattrib = &pmptx->attrib;
+	_rtw_memset(pattrib, 0, sizeof(struct pkt_attrib));
+	_rtw_memset(pmptx->desc, 0, TXDESC_SIZE);
+
+	pattrib->ether_type = 0x8712;
+	_rtw_memset(pattrib->dst, 0xFF, ETH_ALEN);
+
+	/*	pattrib->dhcp_pkt = 0;
+	 *	pattrib->pktlen = 0; */
+	pattrib->ack_policy = 0;
+	/*	pattrib->pkt_hdrlen = ETH_HLEN; */
+	pattrib->hdrlen = WLAN_HDR_A3_LEN;
+	pattrib->subtype = WIFI_DATA;
+	pattrib->priority = 0;
+	pattrib->qsel = pattrib->priority;
+	/*	do_queue_select(padapter, pattrib); */
+	pattrib->nr_frags = 1;
+	pattrib->encrypt = 0;
+	pattrib->bswenc = _FALSE;
+	pattrib->qos_en = _FALSE;
+
+	pattrib->pktlen = 1500;
+
+	if (pHalData->rf_type == RF_1T1R)
+		pattrib->raid = RATEID_IDX_VHT_1SS;
+	else if (pHalData->rf_type == RF_2T2R || pHalData->rf_type == RF_2T4R)
+		pattrib->raid = RATEID_IDX_VHT_2SS;
+	else if (pHalData->rf_type == RF_3T3R)
+		pattrib->raid = RATEID_IDX_VHT_3SS;
+	else
+		pattrib->raid = RATEID_IDX_BGN_40M_1SS;
+}
+
+s32 init_mp_priv(PADAPTER padapter)
+{
+	struct mp_priv *pmppriv = &padapter->mppriv;
+	PHAL_DATA_TYPE pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+
+	_init_mp_priv_(pmppriv);
+	pmppriv->papdater = padapter;
+	pmppriv->mp_dm = 0;
+	pmppriv->tx.stop = 1;
+	pmppriv->bSetTxPower = 0;		/*for  manually set tx power*/
+	pmppriv->bTxBufCkFail = _FALSE;
+	pmppriv->pktInterval = 0;
+	pmppriv->pktLength = 1000;
+
+	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_BC;
+		pmppriv->antenna_rx = ANTENNA_ABCD;
+		break;
+	}
+
+	pHalData->AntennaRxPath = pmppriv->antenna_rx;
+	pHalData->antenna_tx_path = pmppriv->antenna_tx;
+
+	return _SUCCESS;
+}
+
+void free_mp_priv(struct mp_priv *pmp_priv)
+{
+	if (pmp_priv->pallocated_mp_xmitframe_buf) {
+		rtw_mfree(pmp_priv->pallocated_mp_xmitframe_buf, 0);
+		pmp_priv->pallocated_mp_xmitframe_buf = NULL;
+	}
+	pmp_priv->pmp_xmtframe_buf = NULL;
+}
+
+void mpt_InitHWConfig(PADAPTER Adapter)
+{
+	if (IS_HARDWARE_TYPE_8723B(Adapter)) {
+		/* TODO: <20130114, Kordan> The following setting is only for DPDT and Fixed board type. */
+		/* TODO:  A better solution is configure it according EFUSE during the run-time. */
+
+		phy_set_mac_reg(Adapter, 0x64, BIT20, 0x0);		/* 0x66[4]=0		 */
+		phy_set_mac_reg(Adapter, 0x64, BIT24, 0x0);		/* 0x66[8]=0 */
+		phy_set_mac_reg(Adapter, 0x40, BIT4, 0x0);		/* 0x40[4]=0		 */
+		phy_set_mac_reg(Adapter, 0x40, BIT3, 0x1);		/* 0x40[3]=1		 */
+		phy_set_mac_reg(Adapter, 0x4C, BIT24, 0x1);		/* 0x4C[24:23]=10 */
+		phy_set_mac_reg(Adapter, 0x4C, BIT23, 0x0);		/* 0x4C[24:23]=10 */
+		phy_set_bb_reg(Adapter, 0x944, BIT1 | BIT0, 0x3);	/* 0x944[1:0]=11	 */
+		phy_set_bb_reg(Adapter, 0x930, bMaskByte0, 0x77);/* 0x930[7:0]=77	  */
+		phy_set_mac_reg(Adapter, 0x38, BIT11, 0x1);/* 0x38[11]=1 */
+
+		/* TODO: <20130206, Kordan> The default setting is wrong, hard-coded here. */
+		phy_set_mac_reg(Adapter, 0x778, 0x3, 0x3);					/* Turn off hardware PTA control (Asked by Scott) */
+		phy_set_mac_reg(Adapter, 0x64, bMaskDWord, 0x36000000);/* Fix BT S0/S1 */
+		phy_set_mac_reg(Adapter, 0x948, bMaskDWord, 0x0);		/* Fix BT can't Tx */
+
+		/* <20130522, Kordan> Turn off equalizer to improve Rx sensitivity. (Asked by EEChou) */
+		phy_set_bb_reg(Adapter, 0xA00, BIT8, 0x0);			/*0xA01[0] = 0*/
+	} else if (IS_HARDWARE_TYPE_8821(Adapter)) {
+		/* <20131121, VincentL> Add for 8821AU DPDT setting and fix switching antenna issue (Asked by Rock)
+		<20131122, VincentL> Enable for all 8821A/8811AU  (Asked by Alex)*/
+		phy_set_mac_reg(Adapter, 0x4C, BIT23, 0x0);		/*0x4C[23:22]=01*/
+		phy_set_mac_reg(Adapter, 0x4C, BIT22, 0x1);		/*0x4C[23:22]=01*/
+	} else if (IS_HARDWARE_TYPE_8188ES(Adapter))
+		phy_set_mac_reg(Adapter, 0x4C , BIT23, 0);		/*select DPDT_P and DPDT_N as output pin*/
+	else if (IS_HARDWARE_TYPE_8821C(Adapter))
+		PlatformEFIOWrite2Byte(Adapter, REG_RXFLTMAP1_8821C, 0x2000);
+}
+
+static void PHY_IQCalibrate(PADAPTER padapter, u8 bReCovery)
+{
+	PHAL_DATA_TYPE pHalData;
+	u8 b2ant;	/* false:1ant, true:2-ant */
+	u8 RF_Path;	/* 0:S1, 1:S0 */
+
+	if (IS_HARDWARE_TYPE_8723B(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8188E(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8814A(padapter)) {	
+	} else if (IS_HARDWARE_TYPE_8812(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8821(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8192E(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8703B(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8188F(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8822B(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8723D(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8821C(padapter)) {
+		phy_iq_calibrate_8821c(&(GET_HAL_DATA(padapter)->odmpriv), bReCovery);
+	}
+
+}
+
+static void PHY_LCCalibrate(PADAPTER padapter)
+{
+	if (IS_HARDWARE_TYPE_8723B(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8188E(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8814A(padapter)) {	
+	} else if (IS_HARDWARE_TYPE_8812(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8821(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8192E(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8703B(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8188F(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8822B(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8723D(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8821C(padapter)) {
+		/*phy_iq_calibrate_8821c(&(GET_HAL_DATA(padapter)->odmpriv));*/
+	}
+
+}
+
+static u8 PHY_QueryRFPathSwitch(PADAPTER padapter)
+{
+	u8 bmain = 0;
+
+	if (IS_HARDWARE_TYPE_8821C(padapter)) {
+		bmain = phy_query_rf_path_switch_8821c(padapter);
+	}
+
+	return bmain;
+}
+
+static void  PHY_SetRFPathSwitch(PADAPTER padapter , BOOLEAN bMain) {
+
+	if (IS_HARDWARE_TYPE_8723B(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8188E(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8814A(padapter)) {	
+	} else if (IS_HARDWARE_TYPE_8812(padapter) || IS_HARDWARE_TYPE_8821(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8192E(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8703B(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8188F(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8822B(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8723D(padapter)) {
+	} else if (IS_HARDWARE_TYPE_8821C(padapter)) {
+		phy_set_rf_path_switch_8821c(padapter, bMain);
+	}
+}
+
+s32
+MPT_InitializeAdapter(
+	IN	PADAPTER			pAdapter,
+	IN	u8				Channel
+)
+{
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(pAdapter);
+	s32		rtStatus = _SUCCESS;
+	PMPT_CONTEXT	pMptCtx = &pAdapter->mppriv.mpt_ctx;
+	u32		ledsetting;
+	struct mlme_priv *pmlmepriv = &pAdapter->mlmepriv;
+
+	pMptCtx->bMptDrvUnload = _FALSE;
+	pMptCtx->bMassProdTest = _FALSE;
+	pMptCtx->bMptIndexEven = _TRUE;	/* default gain index is -6.0db */
+	pMptCtx->h2cReqNum = 0x0;
+	/* init for BT MP */
+
+	mpt_InitHWConfig(pAdapter);
+
+	pMptCtx->bMptWorkItemInProgress = _FALSE;
+	pMptCtx->CurrMptAct = NULL;
+	pMptCtx->mpt_rf_path = ODM_RF_PATH_A;
+	/* ------------------------------------------------------------------------- */
+	/* Don't accept any packets */
+	rtw_write32(pAdapter, REG_RCR, 0);
+
+	/* ledsetting = rtw_read32(pAdapter, REG_LEDCFG0); */
+	/* rtw_write32(pAdapter, REG_LEDCFG0, ledsetting & ~LED0DIS); */
+
+	/* rtw_write32(pAdapter, REG_LEDCFG0, 0x08080); */
+	ledsetting = rtw_read32(pAdapter, REG_LEDCFG0);
+
+	PHY_LCCalibrate(pAdapter);
+	PHY_IQCalibrate(pAdapter, _FALSE);
+	/* dm_check_txpowertracking(&pHalData->odmpriv);	*/ /* trigger thermal meter */
+
+	PHY_SetRFPathSwitch(pAdapter, 1/*pHalData->bDefaultAntenna*/); /* default use Main */
+
+	pMptCtx->backup0xc50 = (u1Byte)phy_query_bb_reg(pAdapter, rOFDM0_XAAGCCore1, bMaskByte0);
+	pMptCtx->backup0xc58 = (u1Byte)phy_query_bb_reg(pAdapter, rOFDM0_XBAGCCore1, bMaskByte0);
+	pMptCtx->backup0xc30 = (u1Byte)phy_query_bb_reg(pAdapter, rOFDM0_RxDetector1, bMaskByte0);
+	pMptCtx->backup0x52_RF_A = (u1Byte)phy_query_rf_reg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0);
+	pMptCtx->backup0x52_RF_B = (u1Byte)phy_query_rf_reg(pAdapter, RF_PATH_B, RF_0x52, 0x000F0);
+	return	rtStatus;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	MPT_DeInitAdapter()
+ *
+ * Overview:	Extra DeInitialization for Mass Production Test.
+ *
+ * Input:		PADAPTER	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(
+	IN	PADAPTER	pAdapter
+)
+{
+	PMPT_CONTEXT		pMptCtx = &pAdapter->mppriv.mpt_ctx;
+
+	pMptCtx->bMptDrvUnload = _TRUE;
+}
+
+static u8 mpt_ProStartTest(PADAPTER padapter)
+{
+	PMPT_CONTEXT pMptCtx = &padapter->mppriv.mpt_ctx;
+
+	pMptCtx->bMassProdTest = _TRUE;
+	pMptCtx->is_start_cont_tx = _FALSE;
+	pMptCtx->bCckContTx = _FALSE;
+	pMptCtx->bOfdmContTx = _FALSE;
+	pMptCtx->bSingleCarrier = _FALSE;
+	pMptCtx->is_carrier_suppression = _FALSE;
+	pMptCtx->is_single_tone = _FALSE;
+	pMptCtx->HWTxmode = PACKETS_TX;
+
+	return _SUCCESS;
+}
+
+/*
+ * General use
+ */
+s32 SetPowerTracking(PADAPTER padapter, u8 enable)
+{
+
+	hal_mpt_SetPowerTracking(padapter, enable);
+	return 0;
+}
+
+void rtw_mp_trigger_iqk(PADAPTER padapter)
+{
+	PHY_IQCalibrate(padapter, _FALSE);
+}
+
+void rtw_mp_trigger_lck(PADAPTER padapter)
+{
+	PHY_LCCalibrate(padapter);
+}
+
+static void disable_dm(PADAPTER padapter)
+{
+	u8 v8;
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+	struct PHY_DM_STRUCT		*pDM_Odm = &pHalData->odmpriv;
+
+	/* 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 */
+	rtw_phydm_func_disable_all(padapter);
+
+	/* enable APK, LCK and IQK but disable power tracking */
+	pDM_Odm->rf_calibrate_info.txpowertrack_control = _FALSE;
+	rtw_phydm_func_set(padapter, ODM_RF_CALIBRATION);
+
+	/* #ifdef CONFIG_BT_COEXIST */
+	/* rtw_btcoex_Switch(padapter, 0); */ /* remove for BT MP Down. */
+	/* #endif */
+}
+
+void MPT_PwrCtlDM(PADAPTER padapter, u32 bstart)
+{
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+	struct PHY_DM_STRUCT		*pDM_Odm = &pHalData->odmpriv;
+
+	if (bstart == 1) {
+		RTW_INFO("in MPT_PwrCtlDM start\n");
+		rtw_phydm_func_set(padapter, ODM_RF_TX_PWR_TRACK);
+
+		pDM_Odm->rf_calibrate_info.txpowertrack_control = _TRUE;
+		padapter->mppriv.mp_dm = 1;
+
+	} else {
+		RTW_INFO("in MPT_PwrCtlDM stop\n");
+		rtw_phydm_func_clr(padapter, ODM_RF_TX_PWR_TRACK);
+		pDM_Odm->rf_calibrate_info.txpowertrack_control = _FALSE;
+		padapter->mppriv.mp_dm = 0;
+		{
+			struct _TXPWRTRACK_CFG	c;
+			u1Byte	chnl = 0 ;
+			_rtw_memset(&c, 0, sizeof(struct _TXPWRTRACK_CFG));
+			configure_txpower_track(pDM_Odm, &c);
+			odm_clear_txpowertracking_state(pDM_Odm);
+			if (*c.odm_tx_pwr_track_set_pwr) {
+				if (pDM_Odm->support_ic_type == ODM_RTL8188F)
+					(*c.odm_tx_pwr_track_set_pwr)(pDM_Odm, MIX_MODE, ODM_RF_PATH_A, chnl);
+				else if (pDM_Odm->support_ic_type == ODM_RTL8723D) {
+					(*c.odm_tx_pwr_track_set_pwr)(pDM_Odm, BBSWING, ODM_RF_PATH_A, chnl);
+					SetTxPower(padapter);
+				} else {
+					(*c.odm_tx_pwr_track_set_pwr)(pDM_Odm, BBSWING, ODM_RF_PATH_A, chnl);
+					(*c.odm_tx_pwr_track_set_pwr)(pDM_Odm, BBSWING, ODM_RF_PATH_B, chnl);
+				}
+			}
+		}
+	}
+
+}
+
+u32 mp_join(PADAPTER padapter, u8 mode)
+{
+	WLAN_BSSID_EX bssid;
+	struct sta_info *psta;
+	u32 length;
+	u8 val8, join_type;
+	_irqL irqL;
+	s32 res = _SUCCESS;
+
+	struct mp_priv *pmppriv = &padapter->mppriv;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct wlan_network *tgt_network = &pmlmepriv->cur_network;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX		*pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network));
+
+	/* 1. initialize a new WLAN_BSSID_EX */
+	_rtw_memset(&bssid, 0, sizeof(WLAN_BSSID_EX));
+	RTW_INFO("%s ,pmppriv->network_macaddr=%x %x %x %x %x %x\n", __func__,
+		pmppriv->network_macaddr[0], pmppriv->network_macaddr[1], pmppriv->network_macaddr[2], pmppriv->network_macaddr[3], pmppriv->network_macaddr[4],
+		 pmppriv->network_macaddr[5]);
+	_rtw_memcpy(bssid.MacAddress, pmppriv->network_macaddr, ETH_ALEN);
+
+	if (mode == WIFI_FW_ADHOC_STATE) {
+		bssid.Ssid.SsidLength = strlen("mp_pseudo_adhoc");
+		_rtw_memcpy(bssid.Ssid.Ssid, (u8 *)"mp_pseudo_adhoc", bssid.Ssid.SsidLength);
+		bssid.InfrastructureMode = Ndis802_11IBSS;
+		bssid.NetworkTypeInUse = Ndis802_11DS;
+		bssid.IELength = 0;
+		bssid.Configuration.DSConfig = pmppriv->channel;
+
+	} else if (mode == WIFI_FW_STATION_STATE) {
+		bssid.Ssid.SsidLength = strlen("mp_pseudo_STATION");
+		_rtw_memcpy(bssid.Ssid.Ssid, (u8 *)"mp_pseudo_STATION", bssid.Ssid.SsidLength);
+		bssid.InfrastructureMode = Ndis802_11Infrastructure;
+		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;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	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, 0);
+		rtw_indicate_disconnect(padapter, 0, _FALSE);
+		rtw_free_assoc_resources(padapter, 1);
+	}
+	pmppriv->prev_fw_state = get_fwstate(pmlmepriv);
+	/*pmlmepriv->fw_state = WIFI_MP_STATE;*/
+	init_fwstate(pmlmepriv, 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) {
+		/*pmlmepriv->fw_state = pmppriv->prev_fw_state;*/
+		init_fwstate(pmlmepriv, pmppriv->prev_fw_state);
+		res = _FAIL;
+		goto end_of_mp_start_test;
+	}
+	if (mode == WIFI_FW_ADHOC_STATE)
+	set_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
+	else
+		set_fwstate(pmlmepriv, WIFI_STATION_STATE);
+	/* 3 3. join psudo AdHoc */
+	tgt_network->join_res = 1;
+	tgt_network->aid = psta->aid = 1;
+
+	_rtw_memcpy(&padapter->registrypriv.dev_network, &bssid, length);
+	rtw_update_registrypriv_dev_network(padapter);
+	_rtw_memcpy(&tgt_network->network, &padapter->registrypriv.dev_network, padapter->registrypriv.dev_network.Length);
+	_rtw_memcpy(pnetwork, &padapter->registrypriv.dev_network, padapter->registrypriv.dev_network.Length);
+
+	rtw_indicate_connect(padapter);
+	_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+	set_fwstate(pmlmepriv, _FW_LINKED);
+
+end_of_mp_start_test:
+
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+	if (1) { /* (res == _SUCCESS) */
+		/* set MSR to WIFI_FW_ADHOC_STATE */
+		if (mode == WIFI_FW_ADHOC_STATE) {
+			/* set msr to WIFI_FW_ADHOC_STATE */
+			pmlmeinfo->state = WIFI_FW_ADHOC_STATE;
+			Set_MSR(padapter, (pmlmeinfo->state & 0x3));
+
+			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;
+		} else {
+			Set_MSR(padapter, WIFI_FW_STATION_STATE);
+
+			RTW_INFO("%s , pmppriv->network_macaddr =%x %x %x %x %x %x\n", __func__,
+				pmppriv->network_macaddr[0], pmppriv->network_macaddr[1], pmppriv->network_macaddr[2], pmppriv->network_macaddr[3], pmppriv->network_macaddr[4],
+				 pmppriv->network_macaddr[5]);
+
+			rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pmppriv->network_macaddr);
+		}
+	}
+
+	return res;
+}
+/* This function initializes the DUT to the MP test mode */
+s32 mp_start_test(PADAPTER padapter)
+{
+	struct mp_priv *pmppriv = &padapter->mppriv;
+	s32 res = _SUCCESS;
+
+	padapter->registrypriv.mp_mode = 1;
+
+	/* 3 disable dynamic mechanism */
+	disable_dm(padapter);
+	rtl8821c_phy_init_haldm(padapter);
+
+	/* 3 0. update mp_priv */
+
+	if (!RF_TYPE_VALID(padapter->registrypriv.rf_config)) {
+		/*		switch (phal->rf_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);
+
+	mp_join(padapter, WIFI_FW_ADHOC_STATE);
+
+	return res;
+}
+/* ------------------------------------------------------------------------------
+ * This function change the DUT from the MP test mode into normal mode */
+void mp_stop_test(PADAPTER 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;
+
+	_irqL irqL;
+
+	if (pmppriv->mode == MP_ON) {
+		pmppriv->bSetTxPower = 0;
+		_enter_critical_bh(&pmlmepriv->lock, &irqL);
+		if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _FALSE)
+			goto end_of_mp_stop_test;
+
+		/* 3 1. disconnect psudo AdHoc */
+		rtw_indicate_disconnect(padapter, 0, _FALSE);
+
+		/* 3 2. clear psta used in mp test mode.
+		*	rtw_free_assoc_resources(padapter, 1); */
+		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;*/
+		init_fwstate(pmlmepriv, pmppriv->prev_fw_state);
+
+		/* flush the cur_network */
+		_rtw_memset(tgt_network, 0, sizeof(struct wlan_network));
+
+		_clr_fwstate_(pmlmepriv, WIFI_MP_STATE);
+
+end_of_mp_stop_test:
+
+		_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+	}
+}
+
+/*
+ * SetChannel
+ * Description
+ *	Use H2C command to change channel,
+ *	not only modify rf register, but also other setting need to be done.
+ */
+void SetChannel(PADAPTER pAdapter)
+{
+	hal_mpt_SetChannel(pAdapter);
+}
+
+/*
+ * Notice
+ *	Switch bandwitdth may change center frequency(channel)
+ */
+void SetBandwidth(PADAPTER pAdapter)
+{
+	hal_mpt_SetBandwidth(pAdapter);
+
+}
+
+void SetAntenna(PADAPTER pAdapter)
+{
+	hal_mpt_SetAntenna(pAdapter);
+}
+
+int SetTxPower(PADAPTER pAdapter)
+{
+
+	hal_mpt_SetTxPower(pAdapter);
+	return _TRUE;
+}
+
+void SetDataRate(PADAPTER pAdapter)
+{
+	hal_mpt_SetDataRate(pAdapter);
+}
+
+void MP_PHY_SetRFPathSwitch(PADAPTER pAdapter , BOOLEAN bMain)
+{
+
+	PHY_SetRFPathSwitch(pAdapter, bMain);
+
+}
+
+u8 MP_PHY_QueryRFPathSwitch(PADAPTER pAdapter)
+{
+	return PHY_QueryRFPathSwitch(pAdapter);
+}
+
+s32 SetThermalMeter(PADAPTER pAdapter, u8 target_ther)
+{
+	return hal_mpt_SetThermalMeter(pAdapter, target_ther);
+}
+
+void GetThermalMeter(PADAPTER pAdapter, u8 *value)
+{
+	hal_mpt_GetThermalMeter(pAdapter, value);
+}
+
+void SetSingleCarrierTx(PADAPTER pAdapter, u8 bStart)
+{
+	PhySetTxPowerLevel(pAdapter);
+	hal_mpt_SetSingleCarrierTx(pAdapter, bStart);
+}
+
+void SetSingleToneTx(PADAPTER pAdapter, u8 bStart)
+{
+	PhySetTxPowerLevel(pAdapter);
+	hal_mpt_SetSingleToneTx(pAdapter, bStart);
+}
+
+void SetCarrierSuppressionTx(PADAPTER pAdapter, u8 bStart)
+{
+	PhySetTxPowerLevel(pAdapter);
+	hal_mpt_SetCarrierSuppressionTx(pAdapter, bStart);
+}
+
+void SetContinuousTx(PADAPTER pAdapter, u8 bStart)
+{
+	PhySetTxPowerLevel(pAdapter);
+	hal_mpt_SetContinuousTx(pAdapter, bStart);
+}
+
+void PhySetTxPowerLevel(PADAPTER pAdapter)
+{
+	struct mp_priv *pmp_priv = &pAdapter->mppriv;
+
+	if (pmp_priv->bSetTxPower == 0) /* for NO manually set power index */
+		rtw_hal_set_tx_power_level(pAdapter, pmp_priv->channel);
+}
+
+/* ------------------------------------------------------------------------------ */
+static void dump_mpframe(PADAPTER 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 thread_return mp_xmit_packet_thread(thread_context context)
+{
+	struct xmit_frame	*pxmitframe;
+	struct mp_tx		*pmptx;
+	struct mp_priv	*pmp_priv;
+	struct xmit_priv	*pxmitpriv;
+	PADAPTER padapter;
+
+	pmp_priv = (struct mp_priv *)context;
+	pmptx = &pmp_priv->tx;
+	padapter = pmp_priv->papdater;
+	pxmitpriv = &(padapter->xmitpriv);
+
+	thread_enter("RTW_MP_THREAD");
+
+	RTW_INFO("%s:pkTx Start\n", __func__);
+	while (1) {
+		pxmitframe = alloc_mp_xmitframe(pxmitpriv);
+		if (pxmitframe == NULL) {
+			if (pmptx->stop ||
+			    RTW_CANNOT_RUN(padapter))
+				goto exit;
+			else {
+				rtw_usleep_os(10);
+				continue;
+			}
+		}
+		_rtw_memcpy((u8 *)(pxmitframe->buf_addr + TXDESC_OFFSET), pmptx->buf, pmptx->write_size);
+		_rtw_memcpy(&(pxmitframe->attrib), &(pmptx->attrib), sizeof(struct pkt_attrib));
+
+		rtw_usleep_os(padapter->mppriv.pktInterval);
+		dump_mpframe(padapter, pxmitframe);
+
+		pmptx->sended++;
+		pmp_priv->tx_pktcount++;
+
+		if (pmptx->stop ||
+		    RTW_CANNOT_RUN(padapter))
+			goto exit;
+		if ((pmptx->count != 0) &&
+		    (pmptx->count == pmptx->sended))
+			goto exit;
+
+		flush_signals_thread();
+	}
+
+exit:
+	/* RTW_INFO("%s:pkTx Exit\n", __func__); */
+	rtw_mfree(pmptx->pallocated_buf, pmptx->buf_size);
+	pmptx->pallocated_buf = NULL;
+	pmptx->stop = 1;
+
+	thread_exit(NULL);
+	return 0;
+}
+
+void fill_txdesc_for_mp(PADAPTER padapter, u8 *ptxdesc)
+{
+	struct mp_priv *pmp_priv = &padapter->mppriv;
+	_rtw_memcpy(ptxdesc, pmp_priv->tx.desc, TXDESC_SIZE);
+}
+
+static void Rtw_MPSetMacTxEDCA(PADAPTER padapter)
+{
+
+	rtw_write32(padapter, 0x508 , 0x00a422); /* Disable EDCA BE Txop for MP pkt tx adjust Packet interval */
+	/* RTW_INFO("%s:write 0x508~~~~~~ 0x%x\n", __func__,rtw_read32(padapter, 0x508)); */
+	phy_set_mac_reg(padapter, 0x458 , bMaskDWord , 0x0);
+	/*RTW_INFO("%s()!!!!! 0x460 = 0x%x\n" ,__func__, phy_query_bb_reg(padapter, 0x460, bMaskDWord));*/
+	phy_set_mac_reg(padapter, 0x460 , bMaskLWord , 0x0); /* fast EDCA queue packet interval & time out value*/
+	/*phy_set_mac_reg(padapter, ODM_EDCA_VO_PARAM ,bMaskLWord , 0x431C);*/
+	/*phy_set_mac_reg(padapter, ODM_EDCA_BE_PARAM ,bMaskLWord , 0x431C);*/
+	/*phy_set_mac_reg(padapter, ODM_EDCA_BK_PARAM ,bMaskLWord , 0x431C);*/
+	RTW_INFO("%s()!!!!! 0x460 = 0x%x\n" , __func__, phy_query_bb_reg(padapter, 0x460, bMaskDWord));
+
+}
+
+void SetPacketTx(PADAPTER padapter)
+{
+	u8 *ptr, *pkt_start, *pkt_end, *fctrl;
+	u32 pkt_size, offset, startPlace, i;
+	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;
+	_rtw_memcpy(pattrib->src, adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
+	_rtw_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->mbssid = 0;
+
+	pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->pktlen;
+
+	/* 3 2. allocate xmit buffer */
+	pkt_size = pattrib->last_txcmdsz;
+
+	if (pmp_priv->tx.pallocated_buf)
+		rtw_mfree(pmp_priv->tx.pallocated_buf, pmp_priv->tx.buf_size);
+	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) {
+		RTW_INFO("%s: malloc(%d) fail!!\n", __func__, pmp_priv->tx.buf_size);
+		return;
+	}
+	pmp_priv->tx.buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pmp_priv->tx.pallocated_buf), XMITBUF_ALIGN_SZ);
+	ptr = pmp_priv->tx.buf;
+
+	_rtw_memset(pmp_priv->tx.desc, 0, TXDESC_SIZE);
+	pkt_start = ptr;
+	pkt_end = pkt_start + pkt_size;
+
+	/* 3 3. init TX descriptor */
+
+	if (IS_HARDWARE_TYPE_8821C(padapter))
+		rtl8821c_prepare_mp_txdesc(padapter, pmp_priv);
+
+	/* 3 4. make wlan header, make_wlanhdr() */
+	hdr = (struct rtw_ieee80211_hdr *)pkt_start;
+	set_frame_sub_type(&hdr->frame_ctl, pattrib->subtype);
+
+	_rtw_memcpy(hdr->addr1, pattrib->dst, ETH_ALEN); /* DA */
+	_rtw_memcpy(hdr->addr2, pattrib->src, ETH_ALEN); /* SA */
+	_rtw_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;
+	}
+	pmp_priv->TXradomBuffer = rtw_zmalloc(4096);
+	if (pmp_priv->TXradomBuffer == NULL) {
+		RTW_INFO("mp create random buffer fail!\n");
+		goto exit;
+	}
+
+	for (i = 0; i < 4096; i++)
+		pmp_priv->TXradomBuffer[i] = rtw_random32() % 0xFF;
+
+	/* startPlace = (u32)(rtw_random32() % 3450); */
+	_rtw_memcpy(ptr, pmp_priv->TXradomBuffer, pkt_end - ptr);
+	/* _rtw_memset(ptr, payload, pkt_end - ptr); */
+	rtw_mfree(pmp_priv->TXradomBuffer, 4096);
+
+	/* 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))
+		RTW_INFO("Create PktTx Thread Fail !!!!!\n");
+
+	Rtw_MPSetMacTxEDCA(padapter);
+exit:
+	return;
+}
+
+void SetPacketRx(PADAPTER pAdapter, u8 bStartRx, u8 bAB)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+	struct mp_priv *pmppriv = &pAdapter->mppriv;
+
+	if (bStartRx) {
+		pHalData->ReceiveConfig = RCR_AAP | RCR_APM | RCR_AM | RCR_AMF | RCR_HTC_LOC_CTRL;
+		pHalData->ReceiveConfig |= RCR_ACRC32;
+		pHalData->ReceiveConfig |= RCR_APP_PHYST_RXFF | RCR_APP_ICV | RCR_APP_MIC;
+
+		if (pmppriv->bSetRxBssid == _TRUE) {
+			RTW_INFO("%s: pmppriv->network_macaddr=" MAC_FMT "\n", __func__,
+				 MAC_ARG(pmppriv->network_macaddr));
+			pHalData->ReceiveConfig = 0;
+			pHalData->ReceiveConfig |= RCR_CBSSID_DATA | RCR_CBSSID_BCN |RCR_APM | RCR_AM | RCR_AB |RCR_AMF;
+
+			write_bbreg(pAdapter, 0x550, BIT3, bEnable);
+			rtw_write16(pAdapter, REG_RXFLTMAP0, 0xFFEF); /* REG_RXFLTMAP0 (RX Filter Map Group 0) */
+
+		} else {
+			pHalData->ReceiveConfig |= RCR_ADF;
+			/* Accept all data frames */
+			rtw_write16(pAdapter, REG_RXFLTMAP2, 0xFFFF);
+		}
+
+		if (bAB)
+			pHalData->ReceiveConfig |= RCR_AB;
+	} else {
+		pHalData->ReceiveConfig = 0;
+		rtw_write16(pAdapter, REG_RXFLTMAP0, 0xFFFF); /* REG_RXFLTMAP0 (RX Filter Map Group 0) */
+	}
+
+	rtw_write32(pAdapter, REG_RCR, pHalData->ReceiveConfig);
+}
+
+/* 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(PADAPTER pAdapter, u32 point)
+{
+	u32 psd_val = 0;
+
+	u16 psd_reg = 0x910;
+	u16 psd_regL = 0xF44;
+
+	psd_val = rtw_read32(pAdapter, psd_reg);
+
+	psd_val &= 0xFFBFFC00;
+	psd_val |= point;
+
+	rtw_write32(pAdapter, psd_reg, psd_val);
+	rtw_mdelay_os(1);
+	psd_val |= 0x00400000;
+
+	rtw_write32(pAdapter, psd_reg, psd_val);
+	rtw_mdelay_os(1);
+
+	psd_val = rtw_read32(pAdapter, psd_regL);
+	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(PADAPTER pAdapter, u8 *data)
+{
+	u32 i, psd_pts = 0, psd_start = 0, psd_stop = 0;
+	u32 psd_data = 0;
+
+	if (!netif_running(pAdapter->pnetdev)) {
+		return 0;
+	}
+
+	if (check_fwstate(&pAdapter->mlmepriv, WIFI_MP_STATE) == _FALSE) {
+		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);
+
+	data[0] = '\0';
+
+	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;
+}
+
+u8
+mpt_to_mgnt_rate(
+	IN	ULONG	MptRateIdx
+)
+{
+	/* Mapped to MGN_XXX defined in MgntGen.h */
+	switch (MptRateIdx) {
+	/* CCK rate. */
+	case	MPT_RATE_1M:
+		return MGN_1M;
+	case	MPT_RATE_2M:
+		return MGN_2M;
+	case	MPT_RATE_55M:
+		return MGN_5_5M;
+	case	MPT_RATE_11M:
+		return MGN_11M;
+
+	/* OFDM rate. */
+	case	MPT_RATE_6M:
+		return MGN_6M;
+	case	MPT_RATE_9M:
+		return MGN_9M;
+	case	MPT_RATE_12M:
+		return MGN_12M;
+	case	MPT_RATE_18M:
+		return MGN_18M;
+	case	MPT_RATE_24M:
+		return MGN_24M;
+	case	MPT_RATE_36M:
+		return MGN_36M;
+	case	MPT_RATE_48M:
+		return MGN_48M;
+	case	MPT_RATE_54M:
+		return MGN_54M;
+
+	/* HT rate. */
+	case	MPT_RATE_MCS0:
+		return MGN_MCS0;
+	case	MPT_RATE_MCS1:
+		return MGN_MCS1;
+	case	MPT_RATE_MCS2:
+		return MGN_MCS2;
+	case	MPT_RATE_MCS3:
+		return MGN_MCS3;
+	case	MPT_RATE_MCS4:
+		return MGN_MCS4;
+	case	MPT_RATE_MCS5:
+		return MGN_MCS5;
+	case	MPT_RATE_MCS6:
+		return MGN_MCS6;
+	case	MPT_RATE_MCS7:
+		return MGN_MCS7;
+	case	MPT_RATE_MCS8:
+		return MGN_MCS8;
+	case	MPT_RATE_MCS9:
+		return MGN_MCS9;
+	case	MPT_RATE_MCS10:
+		return MGN_MCS10;
+	case	MPT_RATE_MCS11:
+		return MGN_MCS11;
+	case	MPT_RATE_MCS12:
+		return MGN_MCS12;
+	case	MPT_RATE_MCS13:
+		return MGN_MCS13;
+	case	MPT_RATE_MCS14:
+		return MGN_MCS14;
+	case	MPT_RATE_MCS15:
+		return MGN_MCS15;
+	case	MPT_RATE_MCS16:
+		return MGN_MCS16;
+	case	MPT_RATE_MCS17:
+		return MGN_MCS17;
+	case	MPT_RATE_MCS18:
+		return MGN_MCS18;
+	case	MPT_RATE_MCS19:
+		return MGN_MCS19;
+	case	MPT_RATE_MCS20:
+		return MGN_MCS20;
+	case	MPT_RATE_MCS21:
+		return MGN_MCS21;
+	case	MPT_RATE_MCS22:
+		return MGN_MCS22;
+	case	MPT_RATE_MCS23:
+		return MGN_MCS23;
+	case	MPT_RATE_MCS24:
+		return MGN_MCS24;
+	case	MPT_RATE_MCS25:
+		return MGN_MCS25;
+	case	MPT_RATE_MCS26:
+		return MGN_MCS26;
+	case	MPT_RATE_MCS27:
+		return MGN_MCS27;
+	case	MPT_RATE_MCS28:
+		return MGN_MCS28;
+	case	MPT_RATE_MCS29:
+		return MGN_MCS29;
+	case	MPT_RATE_MCS30:
+		return MGN_MCS30;
+	case	MPT_RATE_MCS31:
+		return MGN_MCS31;
+
+	/* VHT rate. */
+	case	MPT_RATE_VHT1SS_MCS0:
+		return MGN_VHT1SS_MCS0;
+	case	MPT_RATE_VHT1SS_MCS1:
+		return MGN_VHT1SS_MCS1;
+	case	MPT_RATE_VHT1SS_MCS2:
+		return MGN_VHT1SS_MCS2;
+	case	MPT_RATE_VHT1SS_MCS3:
+		return MGN_VHT1SS_MCS3;
+	case	MPT_RATE_VHT1SS_MCS4:
+		return MGN_VHT1SS_MCS4;
+	case	MPT_RATE_VHT1SS_MCS5:
+		return MGN_VHT1SS_MCS5;
+	case	MPT_RATE_VHT1SS_MCS6:
+		return MGN_VHT1SS_MCS6;
+	case	MPT_RATE_VHT1SS_MCS7:
+		return MGN_VHT1SS_MCS7;
+	case	MPT_RATE_VHT1SS_MCS8:
+		return MGN_VHT1SS_MCS8;
+	case	MPT_RATE_VHT1SS_MCS9:
+		return MGN_VHT1SS_MCS9;
+	case	MPT_RATE_VHT2SS_MCS0:
+		return MGN_VHT2SS_MCS0;
+	case	MPT_RATE_VHT2SS_MCS1:
+		return MGN_VHT2SS_MCS1;
+	case	MPT_RATE_VHT2SS_MCS2:
+		return MGN_VHT2SS_MCS2;
+	case	MPT_RATE_VHT2SS_MCS3:
+		return MGN_VHT2SS_MCS3;
+	case	MPT_RATE_VHT2SS_MCS4:
+		return MGN_VHT2SS_MCS4;
+	case	MPT_RATE_VHT2SS_MCS5:
+		return MGN_VHT2SS_MCS5;
+	case	MPT_RATE_VHT2SS_MCS6:
+		return MGN_VHT2SS_MCS6;
+	case	MPT_RATE_VHT2SS_MCS7:
+		return MGN_VHT2SS_MCS7;
+	case	MPT_RATE_VHT2SS_MCS8:
+		return MGN_VHT2SS_MCS8;
+	case	MPT_RATE_VHT2SS_MCS9:
+		return MGN_VHT2SS_MCS9;
+	case	MPT_RATE_VHT3SS_MCS0:
+		return MGN_VHT3SS_MCS0;
+	case	MPT_RATE_VHT3SS_MCS1:
+		return MGN_VHT3SS_MCS1;
+	case	MPT_RATE_VHT3SS_MCS2:
+		return MGN_VHT3SS_MCS2;
+	case	MPT_RATE_VHT3SS_MCS3:
+		return MGN_VHT3SS_MCS3;
+	case	MPT_RATE_VHT3SS_MCS4:
+		return MGN_VHT3SS_MCS4;
+	case	MPT_RATE_VHT3SS_MCS5:
+		return MGN_VHT3SS_MCS5;
+	case	MPT_RATE_VHT3SS_MCS6:
+		return MGN_VHT3SS_MCS6;
+	case	MPT_RATE_VHT3SS_MCS7:
+		return MGN_VHT3SS_MCS7;
+	case	MPT_RATE_VHT3SS_MCS8:
+		return MGN_VHT3SS_MCS8;
+	case	MPT_RATE_VHT3SS_MCS9:
+		return MGN_VHT3SS_MCS9;
+	case	MPT_RATE_VHT4SS_MCS0:
+		return MGN_VHT4SS_MCS0;
+	case	MPT_RATE_VHT4SS_MCS1:
+		return MGN_VHT4SS_MCS1;
+	case	MPT_RATE_VHT4SS_MCS2:
+		return MGN_VHT4SS_MCS2;
+	case	MPT_RATE_VHT4SS_MCS3:
+		return MGN_VHT4SS_MCS3;
+	case	MPT_RATE_VHT4SS_MCS4:
+		return MGN_VHT4SS_MCS4;
+	case	MPT_RATE_VHT4SS_MCS5:
+		return MGN_VHT4SS_MCS5;
+	case	MPT_RATE_VHT4SS_MCS6:
+		return MGN_VHT4SS_MCS6;
+	case	MPT_RATE_VHT4SS_MCS7:
+		return MGN_VHT4SS_MCS7;
+	case	MPT_RATE_VHT4SS_MCS8:
+		return MGN_VHT4SS_MCS8;
+	case	MPT_RATE_VHT4SS_MCS9:
+		return MGN_VHT4SS_MCS9;
+
+	case	MPT_RATE_LAST:	/* fully automatiMGN_VHT2SS_MCS1;	 */
+	default:
+		RTW_INFO("<===mpt_to_mgnt_rate(), Invalid Rate: %d!!\n", MptRateIdx);
+		return 0x0;
+	}
+}
+
+u8 HwRateToMPTRate(u8 rate)
+{
+	u8	ret_rate = MGN_1M;
+
+	switch (rate) {
+	case DESC_RATE1M:
+		ret_rate = MPT_RATE_1M;
+		break;
+	case DESC_RATE2M:
+		ret_rate = MPT_RATE_2M;
+		break;
+	case DESC_RATE5_5M:
+		ret_rate = MPT_RATE_55M;
+		break;
+	case DESC_RATE11M:
+		ret_rate = MPT_RATE_11M;
+		break;
+	case DESC_RATE6M:
+		ret_rate = MPT_RATE_6M;
+		break;
+	case DESC_RATE9M:
+		ret_rate = MPT_RATE_9M;
+		break;
+	case DESC_RATE12M:
+		ret_rate = MPT_RATE_12M;
+		break;
+	case DESC_RATE18M:
+		ret_rate = MPT_RATE_18M;
+		break;
+	case DESC_RATE24M:
+		ret_rate = MPT_RATE_24M;
+		break;
+	case DESC_RATE36M:
+		ret_rate = MPT_RATE_36M;
+		break;
+	case DESC_RATE48M:
+		ret_rate = MPT_RATE_48M;
+		break;
+	case DESC_RATE54M:
+		ret_rate = MPT_RATE_54M;
+		break;
+	case DESC_RATEMCS0:
+		ret_rate = MPT_RATE_MCS0;
+		break;
+	case DESC_RATEMCS1:
+		ret_rate = MPT_RATE_MCS1;
+		break;
+	case DESC_RATEMCS2:
+		ret_rate = MPT_RATE_MCS2;
+		break;
+	case DESC_RATEMCS3:
+		ret_rate = MPT_RATE_MCS3;
+		break;
+	case DESC_RATEMCS4:
+		ret_rate = MPT_RATE_MCS4;
+		break;
+	case DESC_RATEMCS5:
+		ret_rate = MPT_RATE_MCS5;
+		break;
+	case DESC_RATEMCS6:
+		ret_rate = MPT_RATE_MCS6;
+		break;
+	case DESC_RATEMCS7:
+		ret_rate = MPT_RATE_MCS7;
+		break;
+	case DESC_RATEMCS8:
+		ret_rate = MPT_RATE_MCS8;
+		break;
+	case DESC_RATEMCS9:
+		ret_rate = MPT_RATE_MCS9;
+		break;
+	case DESC_RATEMCS10:
+		ret_rate = MPT_RATE_MCS10;
+		break;
+	case DESC_RATEMCS11:
+		ret_rate = MPT_RATE_MCS11;
+		break;
+	case DESC_RATEMCS12:
+		ret_rate = MPT_RATE_MCS12;
+		break;
+	case DESC_RATEMCS13:
+		ret_rate = MPT_RATE_MCS13;
+		break;
+	case DESC_RATEMCS14:
+		ret_rate = MPT_RATE_MCS14;
+		break;
+	case DESC_RATEMCS15:
+		ret_rate = MPT_RATE_MCS15;
+		break;
+	case DESC_RATEMCS16:
+		ret_rate = MPT_RATE_MCS16;
+		break;
+	case DESC_RATEMCS17:
+		ret_rate = MPT_RATE_MCS17;
+		break;
+	case DESC_RATEMCS18:
+		ret_rate = MPT_RATE_MCS18;
+		break;
+	case DESC_RATEMCS19:
+		ret_rate = MPT_RATE_MCS19;
+		break;
+	case DESC_RATEMCS20:
+		ret_rate = MPT_RATE_MCS20;
+		break;
+	case DESC_RATEMCS21:
+		ret_rate = MPT_RATE_MCS21;
+		break;
+	case DESC_RATEMCS22:
+		ret_rate = MPT_RATE_MCS22;
+		break;
+	case DESC_RATEMCS23:
+		ret_rate = MPT_RATE_MCS23;
+		break;
+	case DESC_RATEMCS24:
+		ret_rate = MPT_RATE_MCS24;
+		break;
+	case DESC_RATEMCS25:
+		ret_rate = MPT_RATE_MCS25;
+		break;
+	case DESC_RATEMCS26:
+		ret_rate = MPT_RATE_MCS26;
+		break;
+	case DESC_RATEMCS27:
+		ret_rate = MPT_RATE_MCS27;
+		break;
+	case DESC_RATEMCS28:
+		ret_rate = MPT_RATE_MCS28;
+		break;
+	case DESC_RATEMCS29:
+		ret_rate = MPT_RATE_MCS29;
+		break;
+	case DESC_RATEMCS30:
+		ret_rate = MPT_RATE_MCS30;
+		break;
+	case DESC_RATEMCS31:
+		ret_rate = MPT_RATE_MCS31;
+		break;
+	case DESC_RATEVHTSS1MCS0:
+		ret_rate = MPT_RATE_VHT1SS_MCS0;
+		break;
+	case DESC_RATEVHTSS1MCS1:
+		ret_rate = MPT_RATE_VHT1SS_MCS1;
+		break;
+	case DESC_RATEVHTSS1MCS2:
+		ret_rate = MPT_RATE_VHT1SS_MCS2;
+		break;
+	case DESC_RATEVHTSS1MCS3:
+		ret_rate = MPT_RATE_VHT1SS_MCS3;
+		break;
+	case DESC_RATEVHTSS1MCS4:
+		ret_rate = MPT_RATE_VHT1SS_MCS4;
+		break;
+	case DESC_RATEVHTSS1MCS5:
+		ret_rate = MPT_RATE_VHT1SS_MCS5;
+		break;
+	case DESC_RATEVHTSS1MCS6:
+		ret_rate = MPT_RATE_VHT1SS_MCS6;
+		break;
+	case DESC_RATEVHTSS1MCS7:
+		ret_rate = MPT_RATE_VHT1SS_MCS7;
+		break;
+	case DESC_RATEVHTSS1MCS8:
+		ret_rate = MPT_RATE_VHT1SS_MCS8;
+		break;
+	case DESC_RATEVHTSS1MCS9:
+		ret_rate = MPT_RATE_VHT1SS_MCS9;
+		break;
+	case DESC_RATEVHTSS2MCS0:
+		ret_rate = MPT_RATE_VHT2SS_MCS0;
+		break;
+	case DESC_RATEVHTSS2MCS1:
+		ret_rate = MPT_RATE_VHT2SS_MCS1;
+		break;
+	case DESC_RATEVHTSS2MCS2:
+		ret_rate = MPT_RATE_VHT2SS_MCS2;
+		break;
+	case DESC_RATEVHTSS2MCS3:
+		ret_rate = MPT_RATE_VHT2SS_MCS3;
+		break;
+	case DESC_RATEVHTSS2MCS4:
+		ret_rate = MPT_RATE_VHT2SS_MCS4;
+		break;
+	case DESC_RATEVHTSS2MCS5:
+		ret_rate = MPT_RATE_VHT2SS_MCS5;
+		break;
+	case DESC_RATEVHTSS2MCS6:
+		ret_rate = MPT_RATE_VHT2SS_MCS6;
+		break;
+	case DESC_RATEVHTSS2MCS7:
+		ret_rate = MPT_RATE_VHT2SS_MCS7;
+		break;
+	case DESC_RATEVHTSS2MCS8:
+		ret_rate = MPT_RATE_VHT2SS_MCS8;
+		break;
+	case DESC_RATEVHTSS2MCS9:
+		ret_rate = MPT_RATE_VHT2SS_MCS9;
+		break;
+	case DESC_RATEVHTSS3MCS0:
+		ret_rate = MPT_RATE_VHT3SS_MCS0;
+		break;
+	case DESC_RATEVHTSS3MCS1:
+		ret_rate = MPT_RATE_VHT3SS_MCS1;
+		break;
+	case DESC_RATEVHTSS3MCS2:
+		ret_rate = MPT_RATE_VHT3SS_MCS2;
+		break;
+	case DESC_RATEVHTSS3MCS3:
+		ret_rate = MPT_RATE_VHT3SS_MCS3;
+		break;
+	case DESC_RATEVHTSS3MCS4:
+		ret_rate = MPT_RATE_VHT3SS_MCS4;
+		break;
+	case DESC_RATEVHTSS3MCS5:
+		ret_rate = MPT_RATE_VHT3SS_MCS5;
+		break;
+	case DESC_RATEVHTSS3MCS6:
+		ret_rate = MPT_RATE_VHT3SS_MCS6;
+		break;
+	case DESC_RATEVHTSS3MCS7:
+		ret_rate = MPT_RATE_VHT3SS_MCS7;
+		break;
+	case DESC_RATEVHTSS3MCS8:
+		ret_rate = MPT_RATE_VHT3SS_MCS8;
+		break;
+	case DESC_RATEVHTSS3MCS9:
+		ret_rate = MPT_RATE_VHT3SS_MCS9;
+		break;
+	case DESC_RATEVHTSS4MCS0:
+		ret_rate = MPT_RATE_VHT4SS_MCS0;
+		break;
+	case DESC_RATEVHTSS4MCS1:
+		ret_rate = MPT_RATE_VHT4SS_MCS1;
+		break;
+	case DESC_RATEVHTSS4MCS2:
+		ret_rate = MPT_RATE_VHT4SS_MCS2;
+		break;
+	case DESC_RATEVHTSS4MCS3:
+		ret_rate = MPT_RATE_VHT4SS_MCS3;
+		break;
+	case DESC_RATEVHTSS4MCS4:
+		ret_rate = MPT_RATE_VHT4SS_MCS4;
+		break;
+	case DESC_RATEVHTSS4MCS5:
+		ret_rate = MPT_RATE_VHT4SS_MCS5;
+		break;
+	case DESC_RATEVHTSS4MCS6:
+		ret_rate = MPT_RATE_VHT4SS_MCS6;
+		break;
+	case DESC_RATEVHTSS4MCS7:
+		ret_rate = MPT_RATE_VHT4SS_MCS7;
+		break;
+	case DESC_RATEVHTSS4MCS8:
+		ret_rate = MPT_RATE_VHT4SS_MCS8;
+		break;
+	case DESC_RATEVHTSS4MCS9:
+		ret_rate = MPT_RATE_VHT4SS_MCS9;
+		break;
+
+	default:
+		RTW_INFO("hw_rate_to_m_rate(): Non supported Rate [%x]!!!\n", rate);
+		break;
+	}
+	return ret_rate;
+}
+
+u8 rtw_mpRateParseFunc(PADAPTER pAdapter, u8 *targetStr)
+{
+	u16 i = 0;
+	u8 *rateindex_Array[] = { "1M", "2M", "5.5M", "11M", "6M", "9M", "12M", "18M", "24M", "36M", "48M", "54M",
+		"HTMCS0", "HTMCS1", "HTMCS2", "HTMCS3", "HTMCS4", "HTMCS5", "HTMCS6", "HTMCS7",
+		"HTMCS8", "HTMCS9", "HTMCS10", "HTMCS11", "HTMCS12", "HTMCS13", "HTMCS14", "HTMCS15",
+		"HTMCS16", "HTMCS17", "HTMCS18", "HTMCS19", "HTMCS20", "HTMCS21", "HTMCS22", "HTMCS23",
+		"HTMCS24", "HTMCS25", "HTMCS26", "HTMCS27", "HTMCS28", "HTMCS29", "HTMCS30", "HTMCS31",
+		"VHT1MCS0", "VHT1MCS1", "VHT1MCS2", "VHT1MCS3", "VHT1MCS4", "VHT1MCS5", "VHT1MCS6", "VHT1MCS7", "VHT1MCS8", "VHT1MCS9",
+		"VHT2MCS0", "VHT2MCS1", "VHT2MCS2", "VHT2MCS3", "VHT2MCS4", "VHT2MCS5", "VHT2MCS6", "VHT2MCS7", "VHT2MCS8", "VHT2MCS9",
+		"VHT3MCS0", "VHT3MCS1", "VHT3MCS2", "VHT3MCS3", "VHT3MCS4", "VHT3MCS5", "VHT3MCS6", "VHT3MCS7", "VHT3MCS8", "VHT3MCS9",
+		"VHT4MCS0", "VHT4MCS1", "VHT4MCS2", "VHT4MCS3", "VHT4MCS4", "VHT4MCS5", "VHT4MCS6", "VHT4MCS7", "VHT4MCS8", "VHT4MCS9"
+				};
+
+	for (i = 0; i <= 83; i++) {
+		if (strcmp(targetStr, rateindex_Array[i]) == 0) {
+			RTW_INFO("%s , index = %d\n", __func__ , i);
+			return i;
+		}
+	}
+
+	printk("%s ,please input a Data RATE String as:", __func__);
+	for (i = 0; i <= 83; i++) {
+		printk("%s ", rateindex_Array[i]);
+		if (i % 10 == 0)
+			printk("\n");
+	}
+	return _FAIL;
+}
+
+ULONG mpt_ProQueryCalTxPower(
+	PADAPTER	pAdapter,
+	u8		RfPath
+)
+{
+
+	HAL_DATA_TYPE	*pHalData	= GET_HAL_DATA(pAdapter);
+	PMPT_CONTEXT		pMptCtx = &(pAdapter->mppriv.mpt_ctx);
+
+	ULONG			TxPower = 1;
+	u1Byte			rate = 0;
+	struct txpwr_idx_comp tic;
+	u8 mgn_rate = mpt_to_mgnt_rate(pMptCtx->mpt_rate_index);
+
+	TxPower = rtw_hal_get_tx_power_index(pAdapter, RfPath, mgn_rate, pHalData->current_channel_bw, pHalData->current_channel, &tic);
+
+	RTW_INFO("bw=%d, ch=%d, rate=%d, txPower:%u = %u + (%d=%d:%d) + (%d) + (%d)\n",
+		pHalData->current_channel_bw, pHalData->current_channel, mgn_rate
+		, TxPower, tic.base, (tic.by_rate > tic.limit ? tic.limit : tic.by_rate), tic.by_rate, tic.limit, tic.tpt, tic.ebias);
+
+	pAdapter->mppriv.txpoweridx = (u8)TxPower;
+	pMptCtx->TxPwrLevel[ODM_RF_PATH_A] = (u8)TxPower;
+	pMptCtx->TxPwrLevel[ODM_RF_PATH_B] = (u8)TxPower;
+	pMptCtx->TxPwrLevel[ODM_RF_PATH_C] = (u8)TxPower;
+	pMptCtx->TxPwrLevel[ODM_RF_PATH_D]  = (u8)TxPower;
+	hal_mpt_SetTxPower(pAdapter);
+
+	return TxPower;
+}
+
diff --git a/drivers/staging/rtl8821ce/core/rtw_odm.c b/drivers/staging/rtl8821ce/core/rtw_odm.c
new file mode 100644
index 000000000000..58d0aca93765
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/rtw_odm.c
@@ -0,0 +1,380 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * Copyright(c) 2013 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 <rtw_odm.h>
+#include <hal_data.h>
+
+/* set ODM_CMNINFO_IC_TYPE based on chip_type */
+void rtw_odm_init_ic_type(_adapter *adapter)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	struct PHY_DM_STRUCT *odm = &hal_data->odmpriv;
+	u4Byte ic_type = chip_type_to_odm_ic_type(rtw_get_chip_type(adapter));
+
+	rtw_warn_on(!ic_type);
+
+	odm_cmn_info_init(odm, ODM_CMNINFO_IC_TYPE, ic_type);
+}
+
+inline void rtw_odm_set_force_igi_lb(_adapter *adapter, u8 lb)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+
+	hal_data->u1ForcedIgiLb = lb;
+}
+
+inline u8 rtw_odm_get_force_igi_lb(_adapter *adapter)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+
+	return hal_data->u1ForcedIgiLb;
+}
+
+void rtw_odm_adaptivity_ver_msg(void *sel, _adapter *adapter)
+{
+	RTW_PRINT_SEL(sel, "ADAPTIVITY_VERSION "ADAPTIVITY_VERSION"\n");
+}
+
+#define RTW_ADAPTIVITY_EN_DISABLE 0
+#define RTW_ADAPTIVITY_EN_ENABLE 1
+
+void rtw_odm_adaptivity_en_msg(void *sel, _adapter *adapter)
+{
+	struct registry_priv *regsty = &adapter->registrypriv;
+	struct mlme_priv *mlme = &adapter->mlmepriv;
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	struct PHY_DM_STRUCT *odm = &hal_data->odmpriv;
+
+	RTW_PRINT_SEL(sel, "RTW_ADAPTIVITY_EN_");
+
+	if (regsty->adaptivity_en == RTW_ADAPTIVITY_EN_DISABLE)
+		_RTW_PRINT_SEL(sel, "DISABLE\n");
+	else if (regsty->adaptivity_en == RTW_ADAPTIVITY_EN_ENABLE)
+		_RTW_PRINT_SEL(sel, "ENABLE\n");
+	else
+		_RTW_PRINT_SEL(sel, "INVALID\n");
+}
+
+#define RTW_ADAPTIVITY_MODE_NORMAL 0
+#define RTW_ADAPTIVITY_MODE_CARRIER_SENSE 1
+
+void rtw_odm_adaptivity_mode_msg(void *sel, _adapter *adapter)
+{
+	struct registry_priv *regsty = &adapter->registrypriv;
+
+	RTW_PRINT_SEL(sel, "RTW_ADAPTIVITY_MODE_");
+
+	if (regsty->adaptivity_mode == RTW_ADAPTIVITY_MODE_NORMAL)
+		_RTW_PRINT_SEL(sel, "NORMAL\n");
+	else if (regsty->adaptivity_mode == RTW_ADAPTIVITY_MODE_CARRIER_SENSE)
+		_RTW_PRINT_SEL(sel, "CARRIER_SENSE\n");
+	else
+		_RTW_PRINT_SEL(sel, "INVALID\n");
+}
+
+#define RTW_ADAPTIVITY_DML_DISABLE 0
+#define RTW_ADAPTIVITY_DML_ENABLE 1
+
+void rtw_odm_adaptivity_dml_msg(void *sel, _adapter *adapter)
+{
+	struct registry_priv *regsty = &adapter->registrypriv;
+
+	RTW_PRINT_SEL(sel, "RTW_ADAPTIVITY_DML_");
+
+	if (regsty->adaptivity_dml == RTW_ADAPTIVITY_DML_DISABLE)
+		_RTW_PRINT_SEL(sel, "DISABLE\n");
+	else if (regsty->adaptivity_dml == RTW_ADAPTIVITY_DML_ENABLE)
+		_RTW_PRINT_SEL(sel, "ENABLE\n");
+	else
+		_RTW_PRINT_SEL(sel, "INVALID\n");
+}
+
+void rtw_odm_adaptivity_dc_backoff_msg(void *sel, _adapter *adapter)
+{
+	struct registry_priv *regsty = &adapter->registrypriv;
+
+	RTW_PRINT_SEL(sel, "RTW_ADAPTIVITY_DC_BACKOFF:%u\n", regsty->adaptivity_dc_backoff);
+}
+
+void rtw_odm_adaptivity_config_msg(void *sel, _adapter *adapter)
+{
+	rtw_odm_adaptivity_ver_msg(sel, adapter);
+	rtw_odm_adaptivity_en_msg(sel, adapter);
+	rtw_odm_adaptivity_mode_msg(sel, adapter);
+	rtw_odm_adaptivity_dml_msg(sel, adapter);
+	rtw_odm_adaptivity_dc_backoff_msg(sel, adapter);
+}
+
+bool rtw_odm_adaptivity_needed(_adapter *adapter)
+{
+	struct registry_priv *regsty = &adapter->registrypriv;
+	struct mlme_priv *mlme = &adapter->mlmepriv;
+	bool ret = _FALSE;
+
+	if (regsty->adaptivity_en == RTW_ADAPTIVITY_EN_ENABLE)
+		ret = _TRUE;
+
+	return ret;
+}
+
+void rtw_odm_adaptivity_parm_msg(void *sel, _adapter *adapter)
+{
+	HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter);
+	struct PHY_DM_STRUCT *odm = &pHalData->odmpriv;
+
+	rtw_odm_adaptivity_config_msg(sel, adapter);
+
+	RTW_PRINT_SEL(sel, "%10s %16s %16s %22s %12s\n"
+		, "th_l2h_ini", "th_edcca_hl_diff", "th_l2h_ini_mode2", "th_edcca_hl_diff_mode2", "edcca_enable");
+	RTW_PRINT_SEL(sel, "0x%-8x %-16d 0x%-14x %-22d %-12d\n"
+		, (u8)odm->th_l2h_ini
+		, odm->th_edcca_hl_diff
+		, (u8)odm->th_l2h_ini_mode2
+		, odm->th_edcca_hl_diff_mode2
+		, odm->edcca_enable
+	);
+
+	RTW_PRINT_SEL(sel, "%15s %9s\n", "AdapEnableState", "Adap_Flag");
+	RTW_PRINT_SEL(sel, "%-15x %-9x\n"
+		, odm->adaptivity_enable
+		, odm->adaptivity_flag
+	);
+}
+
+void rtw_odm_adaptivity_parm_set(_adapter *adapter, s8 th_l2h_ini, s8 th_edcca_hl_diff, s8 th_l2h_ini_mode2, s8 th_edcca_hl_diff_mode2, u8 edcca_enable)
+{
+	HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter);
+	struct PHY_DM_STRUCT *odm = &pHalData->odmpriv;
+
+	odm->th_l2h_ini = th_l2h_ini;
+	odm->th_edcca_hl_diff = th_edcca_hl_diff;
+	odm->th_l2h_ini_mode2 = th_l2h_ini_mode2;
+	odm->th_edcca_hl_diff_mode2 = th_edcca_hl_diff_mode2;
+	odm->edcca_enable = edcca_enable;
+}
+
+void rtw_odm_get_perpkt_rssi(void *sel, _adapter *adapter)
+{
+	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+	struct PHY_DM_STRUCT *odm = &(hal_data->odmpriv);
+
+	RTW_PRINT_SEL(sel, "rx_rate = %s, RSSI_A = %d(%%), RSSI_B = %d(%%)\n",
+		      HDATA_RATE(odm->rx_rate), odm->RSSI_A, odm->RSSI_B);
+}
+
+void rtw_odm_acquirespinlock(_adapter *adapter,	enum rt_spinlock_type type)
+{
+	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(adapter);
+	_irqL irqL;
+
+	switch (type) {
+	case RT_IQK_SPINLOCK:
+		_enter_critical_bh(&pHalData->IQKSpinLock, &irqL);
+	default:
+		break;
+	}
+}
+
+void rtw_odm_releasespinlock(_adapter *adapter,	enum rt_spinlock_type type)
+{
+	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(adapter);
+	_irqL irqL;
+
+	switch (type) {
+	case RT_IQK_SPINLOCK:
+		_exit_critical_bh(&pHalData->IQKSpinLock, &irqL);
+	default:
+		break;
+	}
+}
+
+inline u8 rtw_odm_get_dfs_domain(_adapter *adapter)
+{
+	return PHYDM_DFS_DOMAIN_UNKNOWN;
+}
+
+inline u8 rtw_odm_dfs_domain_unknown(_adapter *adapter)
+{
+	return 1;
+}
+
+
+void rtw_odm_parse_rx_phy_status_chinfo(union recv_frame *rframe, u8 *phys)
+{
+#ifndef DBG_RX_PHYSTATUS_CHINFO
+#define DBG_RX_PHYSTATUS_CHINFO 0
+#endif
+
+	_adapter *adapter = rframe->u.hdr.adapter;
+	struct PHY_DM_STRUCT *phydm = GET_ODM(adapter);
+	struct rx_pkt_attrib *attrib = &rframe->u.hdr.attrib;
+	u8 *wlanhdr = get_recvframe_data(rframe);
+
+	if (phydm->support_ic_type & ODM_IC_PHY_STATUE_NEW_TYPE) {
+		/*
+		* 8723D:
+		* type_0(CCK)
+		*     l_rxsc
+		*         is filled with primary channel SC, not real rxsc.
+		*         0:LSC, 1:USC
+		* type_1(OFDM)
+		*     rf_mode
+		*         RF bandwidth when RX
+		*     l_rxsc(legacy), ht_rxsc
+		*         see below RXSC N-series
+		* type_2(Not used)
+		*/
+		/*
+		* 8821C, 8822B:
+		* type_0(CCK)
+		*     l_rxsc
+		*         is filled with primary channel SC, not real rxsc.
+		*         0:LSC, 1:USC
+		* type_1(OFDM)
+		*     rf_mode
+		*         RF bandwidth when RX
+		*     l_rxsc(legacy), ht_rxsc
+		*         see below RXSC AC-series
+		* type_2(Not used)
+		*/
+
+		if ((*phys & 0xf) == 0) {
+			struct _phy_status_rpt_jaguar2_type0 *phys_t0 = (struct _phy_status_rpt_jaguar2_type0 *)phys;
+
+			if (DBG_RX_PHYSTATUS_CHINFO) {
+				RTW_PRINT("phys_t%u ta="MAC_FMT" %s, %s(band:%u, ch:%u, l_rxsc:%u)\n"
+					, *phys & 0xf
+					, MAC_ARG(get_ta(wlanhdr))
+					, is_broadcast_mac_addr(get_ra(wlanhdr)) ? "BC" : is_multicast_mac_addr(get_ra(wlanhdr)) ? "MC" : "UC"
+					, HDATA_RATE(attrib->data_rate)
+					, phys_t0->band, phys_t0->channel, phys_t0->rxsc
+				);
+			}
+
+		} else if ((*phys & 0xf) == 1) {
+			struct _phy_status_rpt_jaguar2_type1 *phys_t1 = (struct _phy_status_rpt_jaguar2_type1 *)phys;
+			u8 rxsc = (attrib->data_rate > DESC_RATE11M && attrib->data_rate < DESC_RATEMCS0) ? phys_t1->l_rxsc : phys_t1->ht_rxsc;
+			u8 pkt_cch = 0;
+			u8 pkt_bw = CHANNEL_WIDTH_20;
+
+
+			if (phydm->support_ic_type & ODM_IC_11AC_SERIES) {
+				/* RXSC AC-series */
+				#define RXSC_DUP			0 /* 0: RX from all SC of current rf_mode */
+
+				#define RXSC_LL20M_OF_160M	8 /* 1~8: RX from 20MHz SC */
+				#define RXSC_L20M_OF_160M	6
+				#define RXSC_L20M_OF_80M	4
+				#define RXSC_L20M_OF_40M	2
+				#define RXSC_U20M_OF_40M	1
+				#define RXSC_U20M_OF_80M	3
+				#define RXSC_U20M_OF_160M	5
+				#define RXSC_UU20M_OF_160M	7
+
+				#define RXSC_L40M_OF_160M	12 /* 9~12: RX from 40MHz SC */
+				#define RXSC_L40M_OF_80M	10
+				#define RXSC_U40M_OF_80M	9
+				#define RXSC_U40M_OF_160M	11
+
+				#define RXSC_L80M_OF_160M	14 /* 13~14: RX from 80MHz SC */
+				#define RXSC_U80M_OF_160M	13
+
+				static const s8 cch_offset_by_rxsc[15] = {0, 2, -2, 6, -6, 10, -10, 14, -14, 4, -4, 12, -12, 8, -8};
+
+				if (phys_t1->rf_mode > 3) {
+					/* invalid rf_mode */
+					rtw_warn_on(1);
+					goto type1_end;
+				}
+
+				if (phys_t1->rf_mode == 0) {
+					/* RF 20MHz */
+					pkt_cch = phys_t1->channel;
+					pkt_bw = CHANNEL_WIDTH_20;
+					goto type1_end;
+				}
+
+				if (rxsc == 0) {
+					/* RF and RX with same BW */
+					if (attrib->data_rate >= DESC_RATEMCS0) {
+						pkt_cch = phys_t1->channel;
+						pkt_bw = phys_t1->rf_mode;
+					}
+					goto type1_end;
+				}
+
+				if ((phys_t1->rf_mode == 1 && rxsc >= 1 && rxsc <= 2) /* RF 40MHz, RX 20MHz */
+					|| (phys_t1->rf_mode == 2 && rxsc >= 1 && rxsc <= 4) /* RF 80MHz, RX 20MHz */
+					|| (phys_t1->rf_mode == 3 && rxsc >= 1 && rxsc <= 8) /* RF 160MHz, RX 20MHz */
+				) {
+					pkt_cch = phys_t1->channel + cch_offset_by_rxsc[rxsc];
+					pkt_bw = CHANNEL_WIDTH_20;
+				} else if ((phys_t1->rf_mode == 2 && rxsc >= 9 && rxsc <= 10) /* RF 80MHz, RX 40MHz */
+					|| (phys_t1->rf_mode == 3 && rxsc >= 9 && rxsc <= 12) /* RF 160MHz, RX 40MHz */
+				) {
+					if (attrib->data_rate >= DESC_RATEMCS0) {
+						pkt_cch = phys_t1->channel + cch_offset_by_rxsc[rxsc];
+						pkt_bw = CHANNEL_WIDTH_40;
+					}
+				} else if ((phys_t1->rf_mode == 3 && rxsc >= 13 && rxsc <= 14) /* RF 160MHz, RX 80MHz */
+				) {
+					if (attrib->data_rate >= DESC_RATEMCS0) {
+						pkt_cch = phys_t1->channel + cch_offset_by_rxsc[rxsc];
+						pkt_bw = CHANNEL_WIDTH_80;
+					}
+				} else
+					rtw_warn_on(1);
+
+			}
+
+type1_end:
+			if (DBG_RX_PHYSTATUS_CHINFO) {
+				RTW_PRINT("phys_t%u ta="MAC_FMT" %s, %s(band:%u, ch:%u, rf_mode:%u, l_rxsc:%u, ht_rxsc:%u) => %u,%u\n"
+					, *phys & 0xf
+					, MAC_ARG(get_ta(wlanhdr))
+					, is_broadcast_mac_addr(get_ra(wlanhdr)) ? "BC" : is_multicast_mac_addr(get_ra(wlanhdr)) ? "MC" : "UC"
+					, HDATA_RATE(attrib->data_rate)
+					, phys_t1->band, phys_t1->channel, phys_t1->rf_mode, phys_t1->l_rxsc, phys_t1->ht_rxsc
+					, pkt_cch, pkt_bw
+				);
+			}
+
+			/* for now, only return cneter channel of 20MHz packet */
+			if (pkt_cch && pkt_bw == CHANNEL_WIDTH_20)
+				attrib->ch = pkt_cch;
+
+		} else {
+			struct _phy_status_rpt_jaguar2_type2 *phys_t2 = (struct _phy_status_rpt_jaguar2_type2 *)phys;
+
+			if (DBG_RX_PHYSTATUS_CHINFO) {
+				RTW_PRINT("phys_t%u ta="MAC_FMT" %s, %s(band:%u, ch:%u, l_rxsc:%u, ht_rxsc:%u)\n"
+					, *phys & 0xf
+					, MAC_ARG(get_ta(wlanhdr))
+					, is_broadcast_mac_addr(get_ra(wlanhdr)) ? "BC" : is_multicast_mac_addr(get_ra(wlanhdr)) ? "MC" : "UC"
+					, HDATA_RATE(attrib->data_rate)
+					, phys_t2->band, phys_t2->channel, phys_t2->l_rxsc, phys_t2->ht_rxsc
+				);
+			}
+		}
+	}
+
+}
+
diff --git a/drivers/staging/rtl8821ce/core/rtw_p2p.c b/drivers/staging/rtl8821ce/core/rtw_p2p.c
new file mode 100644
index 000000000000..5238f8c6e48d
--- /dev/null
+++ b/drivers/staging/rtl8821ce/core/rtw_p2p.c
@@ -0,0 +1,3661 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/******************************************************************************
+ *
+ * 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 <drv_types.h>
+
+
+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 ;
+}
+
+int is_any_client_associated(_adapter *padapter)
+{
+	return padapter->stapriv.asoc_list_cnt ? _TRUE : _FALSE;
+}
+
+static u32 go_add_group_info_attr(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+	_irqL irqL;
+	_list	*phead, *plist;
+	u32 len = 0;
+	u16 attr_len = 0;
+	u8 tmplen, *pdata_attr, *pstart, *pcur;
+	struct sta_info *psta = NULL;
+	_adapter *padapter = pwdinfo->padapter;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
+
+	pdata_attr = rtw_zmalloc(MAX_P2P_IE_LEN);
+
+	if (NULL == pdata_attr) {
+		RTW_INFO("%s pdata_attr malloc failed\n", __FUNCTION__);
+		goto _exit;
+	}
+
+	pstart = pdata_attr;
+	pcur = pdata_attr;
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+
+	/* look up sta asoc_queue */
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+
+		plist = get_next(plist);
+
+		if (psta->is_p2p_device) {
+			tmplen = 0;
+
+			pcur++;
+
+			/* P2P device address */
+			_rtw_memcpy(pcur, psta->dev_addr, ETH_ALEN);
+			pcur += ETH_ALEN;
+
+			/* P2P interface address */
+			_rtw_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;
+
+			_rtw_memcpy(pcur, psta->primary_dev_type, 8);
+			pcur += 8;
+
+			*pcur = psta->num_of_secdev_type;
+			pcur++;
+
+			_rtw_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;
+
+				_rtw_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;
+
+		}
+
+	}
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	if (attr_len > 0)
+		len = rtw_set_p2p_attr_content(pbuf, P2P_ATTR_GROUP_INFO, attr_len, pdata_attr);
+
+	rtw_mfree(pdata_attr, MAX_P2P_IE_LEN);
+
+_exit:
+	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;
+	unsigned short				*fctrl;
+	_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	 */
+	u32	p2poui = cpu_to_be32(P2POUI);
+	u8	oui_subtype = P2P_GO_DISC_REQUEST;
+	u8	dialogToken = 0;
+
+	RTW_INFO("[%s]\n", __FUNCTION__);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_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;
+
+	_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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;
+	unsigned short				*fctrl;
+	_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;
+	u32			p2poui = cpu_to_be32(P2POUI);
+	u8			oui_subtype = P2P_DEVDISC_RESP;
+	u8 p2pie[8] = { 0x00 };
+	u32 p2pielen = 0;
+
+	RTW_INFO("[%s]\n", __FUNCTION__);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_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;
+
+	_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, pwdinfo->device_addr, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, pwdinfo->device_addr, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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)
+{
+	_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. */
+	u32			p2poui = cpu_to_be32(P2POUI);
+	u8			oui_subtype = P2P_PROVISION_DISC_RESP;
+	u8			wpsie[100] = { 0x00 };
+	u8			wpsielen = 0;
+	u32					wfdielen = 0;
+
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	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);
+
+	_rtw_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;
+
+	_rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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 */
+	/* *(u32*) ( wpsie ) = cpu_to_be32( WPSOUI ); */
+	RTW_PUT_BE32(wpsie, WPSOUI);
+	wpsielen += 4;
+
+	/*	Config Method */
+	/*	Type: */
+	/* *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_CONF_METHOD ); */
+	RTW_PUT_BE16(wpsie + wpsielen, WPS_ATTR_CONF_METHOD);
+	wpsielen += 2;
+
+	/*	Length: */
+	/* *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0002 ); */
+	RTW_PUT_BE16(wpsie + wpsielen, 0x0002);
+	wpsielen += 2;
+
+	/*	Value: */
+	/* *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( config_method ); */
+	RTW_PUT_BE16(wpsie + wpsielen, config_method);
+	wpsielen += 2;
+
+	pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen);
+
+	wfdielen = build_provdisc_resp_wfd_ie(pwdinfo, pframe);
+	pframe += wfdielen;
+	pattrib->pktlen += wfdielen;
+
+	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;
+	unsigned short				*fctrl;
+	_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	 */
+	u32	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;
+
+	RTW_INFO("[%s]\n", __FUNCTION__);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_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;
+
+	_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	set_frame_sub_type(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;
+
+	/*	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);
+
+	capability = cpu_to_le16(capability);
+
+	p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_CAPABILITY, 2, (u8 *)&capability);
+
+	/* 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: */
+
+	/* go_add_noa_attr(pwdinfo); */
+
+	pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len);
+
+	return len;
+
+}
+
+u32 build_beacon_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+	u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 };
+	u16 val16 = 0;
+	u32 len = 0, wfdielen = 0;
+	_adapter *padapter = pwdinfo->padapter;
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	struct wifi_display_info	*pwfd_info = padapter->wdinfo.wfd_info;
+
+	if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST))
+		goto exit;
+
+	/*	WFD OUI */
+	wfdielen = 0;
+	wfdie[wfdielen++] = 0x50;
+	wfdie[wfdielen++] = 0x6F;
+	wfdie[wfdielen++] = 0x9A;
+	wfdie[wfdielen++] = 0x0A;	/*	WFA WFD v1.0 */
+
+	/*	Commented by Albert 20110812 */
+	/*	According to the WFD Specification, the beacon frame should contain 4 WFD attributes */
+	/*	1. WFD Device Information */
+	/*	2. Associated BSSID */
+	/*	3. Coupled Sink Information */
+
+	/*	WFD Device Information ATTR */
+	/*	Type: */
+	wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO;
+
+	/*	Length: */
+	/*	Note: In the WFD specification, the size of length field is 2. */
+	RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
+	wfdielen += 2;
+
+	/*	Value1: */
+	/*	WFD device information */
+
+	if (P2P_ROLE_GO == pwdinfo->role) {
+		if (is_any_client_associated(pwdinfo->padapter)) {
+			/*	WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) */
+			val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_WSD;
+			RTW_PUT_BE16(wfdie + wfdielen, val16);
+		} else {
+			/*	WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */
+			val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD;
+			RTW_PUT_BE16(wfdie + wfdielen, val16);
+		}
+
+	} else {
+		/*	WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */
+		val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD;
+		RTW_PUT_BE16(wfdie + wfdielen, val16);
+	}
+
+	wfdielen += 2;
+
+	/*	Value2: */
+	/*	Session Management Control Port */
+	/*	Default TCP port for RTSP messages is 554 */
+	RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport);
+	wfdielen += 2;
+
+	/*	Value3: */
+	/*	WFD Device Maximum Throughput */
+	/*	300Mbps is the maximum throughput */
+	RTW_PUT_BE16(wfdie + wfdielen, 300);
+	wfdielen += 2;
+
+	/*	Associated BSSID ATTR */
+	/*	Type: */
+	wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID;
+
+	/*	Length: */
+	/*	Note: In the WFD specification, the size of length field is 2. */
+	RTW_PUT_BE16(wfdie + wfdielen, 0x0006);
+	wfdielen += 2;
+
+	/*	Value: */
+	/*	Associated BSSID */
+	if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
+		_rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
+	else
+		_rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN);
+
+	wfdielen += ETH_ALEN;
+
+	/*	Coupled Sink Information ATTR */
+	/*	Type: */
+	wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO;
+
+	/*	Length: */
+	/*	Note: In the WFD specification, the size of length field is 2. */
+	RTW_PUT_BE16(wfdie + wfdielen, 0x0007);
+	wfdielen += 2;
+
+	/*	Val