staging: r8188eu: Add source files for new driver - part 1
authorLarry Finger <Larry.Finger@lwfinger.net>
Thu, 22 Aug 2013 03:33:43 +0000 (22:33 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 22 Aug 2013 17:19:59 +0000 (10:19 -0700)
This commit adds core/rtw_ap.c, core/rtw_br_ext.c, and core/rtw_cmd.c

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/rtl8188eu/core/rtw_ap.c [new file with mode: 0644]
drivers/staging/rtl8188eu/core/rtw_br_ext.c [new file with mode: 0644]
drivers/staging/rtl8188eu/core/rtw_cmd.c [new file with mode: 0644]

diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c
new file mode 100644 (file)
index 0000000..2c73823
--- /dev/null
@@ -0,0 +1,1988 @@
+/******************************************************************************
+ *
+ * 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 <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+#include <ieee80211.h>
+
+#ifdef CONFIG_88EU_AP_MODE
+
+void init_mlme_ap_info(struct adapter *padapter)
+{
+       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+
+
+       _rtw_spinlock_init(&pmlmepriv->bcn_update_lock);
+
+       /* for ACL */
+       _rtw_init_queue(&pacl_list->acl_node_q);
+
+       start_ap_mode(padapter);
+}
+
+void free_mlme_ap_info(struct adapter *padapter)
+{
+       unsigned long irqL;
+       struct sta_info *psta = NULL;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info    *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+       pmlmepriv->update_bcn = false;
+       pmlmeext->bstart_bss = false;
+
+       rtw_sta_flush(padapter);
+
+       pmlmeinfo->state = _HW_STATE_NOLINK_;
+
+       /* free_assoc_sta_resources */
+       rtw_free_all_stainfo(padapter);
+
+       /* free bc/mc sta_info */
+       psta = rtw_get_bcmc_stainfo(padapter);
+       _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+       rtw_free_stainfo(padapter, psta);
+       _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+
+       _rtw_spinlock_free(&pmlmepriv->bcn_update_lock);
+}
+
+static void update_BCNTIM(struct adapter *padapter)
+{
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+       struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+       struct wlan_bssid_ex *pnetwork_mlmeext = &(pmlmeinfo->network);
+       unsigned char *pie = pnetwork_mlmeext->IEs;
+
+       /* update TIM IE */
+       if (true) {
+               u8 *p, *dst_ie, *premainder_ie = NULL;
+               u8 *pbackup_remainder_ie = NULL;
+               __le16 tim_bitmap_le;
+               uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen;
+
+               tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap);
+
+               p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, _TIM_IE_, &tim_ielen, pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_);
+               if (p != NULL && tim_ielen > 0) {
+                       tim_ielen += 2;
+                       premainder_ie = p+tim_ielen;
+                       tim_ie_offset = (int)(p - pie);
+                       remainder_ielen = pnetwork_mlmeext->IELength - tim_ie_offset - tim_ielen;
+                       /* append TIM IE from dst_ie offset */
+                       dst_ie = p;
+               } else {
+                       tim_ielen = 0;
+
+                       /* calucate head_len */
+                       offset = _FIXED_IE_LENGTH_;
+                       offset += pnetwork_mlmeext->Ssid.SsidLength + 2;
+
+                       /*  get supported rates len */
+                       p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_));
+                       if (p !=  NULL)
+                               offset += tmp_len+2;
+
+                       /* DS Parameter Set IE, len = 3 */
+                       offset += 3;
+
+                       premainder_ie = pie + offset;
+
+                       remainder_ielen = pnetwork_mlmeext->IELength - offset - tim_ielen;
+
+                       /* append TIM IE from offset */
+                       dst_ie = pie + offset;
+               }
+
+               if (remainder_ielen > 0) {
+                       pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+                       if (pbackup_remainder_ie && premainder_ie)
+                               memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+               }
+               *dst_ie++ = _TIM_IE_;
+
+               if ((pstapriv->tim_bitmap&0xff00) && (pstapriv->tim_bitmap&0x00fc))
+                       tim_ielen = 5;
+               else
+                       tim_ielen = 4;
+
+               *dst_ie++ = tim_ielen;
+
+               *dst_ie++ = 0;/* DTIM count */
+               *dst_ie++ = 1;/* DTIM peroid */
+
+               if (pstapriv->tim_bitmap&BIT(0))/* for bc/mc frames */
+                       *dst_ie++ = BIT(0);/* bitmap ctrl */
+               else
+                       *dst_ie++ = 0;
+
+               if (tim_ielen == 4) {
+                       *dst_ie++ = *(u8 *)&tim_bitmap_le;
+               } else if (tim_ielen == 5) {
+                       memcpy(dst_ie, &tim_bitmap_le, 2);
+                       dst_ie += 2;
+               }
+
+               /* copy remainder IE */
+               if (pbackup_remainder_ie) {
+                       memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+                       kfree(pbackup_remainder_ie);
+               }
+               offset =  (uint)(dst_ie - pie);
+               pnetwork_mlmeext->IELength = offset + remainder_ielen;
+       }
+
+       set_tx_beacon_cmd(padapter);
+}
+
+void rtw_add_bcn_ie(struct adapter *padapter, struct wlan_bssid_ex *pnetwork, u8 index, u8 *data, u8 len)
+{
+       struct ndis_802_11_var_ie *pIE;
+       u8 bmatch = false;
+       u8 *pie = pnetwork->IEs;
+       u8 *p = NULL, *dst_ie = NULL, *premainder_ie = NULL;
+       u8 *pbackup_remainder_ie = NULL;
+       u32 i, offset, ielen = 0, ie_offset, remainder_ielen = 0;
+
+       for (i = sizeof(struct ndis_802_11_fixed_ie); i < pnetwork->IELength;) {
+               pIE = (struct ndis_802_11_var_ie *)(pnetwork->IEs + i);
+
+               if (pIE->ElementID > index) {
+                       break;
+               } else if (pIE->ElementID == index) { /*  already exist the same IE */
+                       p = (u8 *)pIE;
+                       ielen = pIE->Length;
+                       bmatch = true;
+                       break;
+               }
+               p = (u8 *)pIE;
+               ielen = pIE->Length;
+               i += (pIE->Length + 2);
+       }
+
+       if (p != NULL && ielen > 0) {
+               ielen += 2;
+
+               premainder_ie = p+ielen;
+
+               ie_offset = (int)(p - pie);
+
+               remainder_ielen = pnetwork->IELength - ie_offset - ielen;
+
+               if (bmatch)
+                       dst_ie = p;
+               else
+                       dst_ie = (p+ielen);
+       }
+
+       if (remainder_ielen > 0) {
+               pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+               if (pbackup_remainder_ie && premainder_ie)
+                       memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+       }
+
+       *dst_ie++ = index;
+       *dst_ie++ = len;
+
+       memcpy(dst_ie, data, len);
+       dst_ie += len;
+
+       /* copy remainder IE */
+       if (pbackup_remainder_ie) {
+               memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+               kfree(pbackup_remainder_ie);
+       }
+
+       offset =  (uint)(dst_ie - pie);
+       pnetwork->IELength = offset + remainder_ielen;
+}
+
+void rtw_remove_bcn_ie(struct adapter *padapter, struct wlan_bssid_ex *pnetwork, u8 index)
+{
+       u8 *p, *dst_ie = NULL, *premainder_ie = NULL;
+       u8 *pbackup_remainder_ie = NULL;
+       uint offset, ielen, ie_offset, remainder_ielen = 0;
+       u8      *pie = pnetwork->IEs;
+
+       p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, index, &ielen,
+                      pnetwork->IELength - _FIXED_IE_LENGTH_);
+       if (p != NULL && ielen > 0) {
+               ielen += 2;
+
+               premainder_ie = p+ielen;
+
+               ie_offset = (int)(p - pie);
+
+               remainder_ielen = pnetwork->IELength - ie_offset - ielen;
+
+               dst_ie = p;
+       }
+
+       if (remainder_ielen > 0) {
+               pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+               if (pbackup_remainder_ie && premainder_ie)
+                       memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+       }
+
+       /* copy remainder IE */
+       if (pbackup_remainder_ie) {
+               memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+               kfree(pbackup_remainder_ie);
+       }
+
+       offset =  (uint)(dst_ie - pie);
+       pnetwork->IELength = offset + remainder_ielen;
+}
+
+static u8 chk_sta_is_alive(struct sta_info *psta)
+{
+       u8 ret = false;
+
+       if ((psta->sta_stats.last_rx_data_pkts + psta->sta_stats.last_rx_ctrl_pkts) ==
+           (psta->sta_stats.rx_data_pkts + psta->sta_stats.rx_ctrl_pkts))
+               ;
+       else
+               ret = true;
+
+       sta_update_last_rx_pkts(psta);
+
+       return ret;
+}
+
+void   expire_timeout_chk(struct adapter *padapter)
+{
+       unsigned long irqL;
+       struct list_head *phead, *plist;
+       u8 updated = 0;
+       struct sta_info *psta = NULL;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       u8 chk_alive_num = 0;
+       char chk_alive_list[NUM_STA];
+       int i;
+
+       _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--;
+
+                               DBG_88E("auth expire %6ph\n",
+                                       psta->hwaddr);
+
+                               _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;
+
+                                       /* to update bcn with tim_bitmap for this station */
+                                       pstapriv->tim_bitmap |= BIT(psta->aid);
+                                       update_beacon(padapter, _TIM_IE_, NULL, false);
+
+                                       if (!pmlmeext->active_keep_alive_check)
+                                               continue;
+                               }
+                       }
+                       if (pmlmeext->active_keep_alive_check) {
+                               int stainfo_offset;
+
+                               stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
+                               if (stainfo_offset_valid(stainfo_offset))
+                                       chk_alive_list[chk_alive_num++] = stainfo_offset;
+                               continue;
+                       }
+
+                       rtw_list_delete(&psta->asoc_list);
+                       pstapriv->asoc_list_cnt--;
+
+                       DBG_88E("asoc expire %pM, state = 0x%x\n", (psta->hwaddr), psta->state);
+                       updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
+               } else {
+                       /* TODO: Aging mechanism to digest frames in sleep_q to avoid running out of xmitframe */
+                       if (psta->sleepq_len > (NR_XMITFRAME/pstapriv->asoc_list_cnt) &&
+                           padapter->xmitpriv.free_xmitframe_cnt < (NR_XMITFRAME/pstapriv->asoc_list_cnt/2)) {
+                               DBG_88E("%s sta:%pM, sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", __func__,
+                                       (psta->hwaddr), psta->sleepq_len,
+                                       padapter->xmitpriv.free_xmitframe_cnt,
+                                       pstapriv->asoc_list_cnt);
+                               wakeup_sta_to_xmit(padapter, psta);
+                       }
+               }
+       }
+
+       _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+       if (chk_alive_num) {
+               u8 backup_oper_channel = 0;
+               struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+               /* switch to correct channel of current network  before issue keep-alive frames */
+               if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) {
+                       backup_oper_channel = rtw_get_oper_ch(padapter);
+                       SelectChannel(padapter, pmlmeext->cur_channel);
+               }
+
+               /* issue null data to check sta alive*/
+               for (i = 0; i < chk_alive_num; i++) {
+                       int ret = _FAIL;
+
+                       psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
+
+                       if (psta->state & WIFI_SLEEP_STATE)
+                               ret = issue_nulldata(padapter, psta->hwaddr, 0, 1, 50);
+                       else
+                               ret = issue_nulldata(padapter, psta->hwaddr, 0, 3, 50);
+
+                       psta->keep_alive_trycnt++;
+                       if (ret == _SUCCESS) {
+                               DBG_88E("asoc check, sta(%pM) is alive\n", (psta->hwaddr));
+                               psta->expire_to = pstapriv->expire_to;
+                               psta->keep_alive_trycnt = 0;
+                               continue;
+                       } else if (psta->keep_alive_trycnt <= 3) {
+                               DBG_88E("ack check for asoc expire, keep_alive_trycnt =%d\n", psta->keep_alive_trycnt);
+                               psta->expire_to = 1;
+                               continue;
+                       }
+
+                       psta->keep_alive_trycnt = 0;
+
+                       DBG_88E("asoc expire %pM, state = 0x%x\n", (psta->hwaddr), psta->state);
+                       _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+                       rtw_list_delete(&psta->asoc_list);
+                       pstapriv->asoc_list_cnt--;
+                       updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
+                       _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+               }
+
+               if (backup_oper_channel > 0) /* back to the original operation channel */
+                       SelectChannel(padapter, backup_oper_channel);
+       }
+
+       associated_clients_update(padapter, updated);
+}
+
+void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level)
+{
+       int i;
+       u8 rf_type;
+       u32 init_rate = 0;
+       unsigned char sta_band = 0, raid, shortGIrate = false;
+       unsigned char limit;
+       unsigned int tx_ra_bitmap = 0;
+       struct ht_priv  *psta_ht = NULL;
+       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+       struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
+
+       if (psta)
+               psta_ht = &psta->htpriv;
+       else
+               return;
+
+       if (!(psta->state & _FW_LINKED))
+               return;
+
+       /* b/g mode ra_bitmap */
+       for (i = 0; i < sizeof(psta->bssrateset); i++) {
+               if (psta->bssrateset[i])
+                       tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i]&0x7f);
+       }
+       /* n mode ra_bitmap */
+       if (psta_ht->ht_option) {
+               rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+               if (rf_type == RF_2T2R)
+                       limit = 16;/*  2R */
+               else
+                       limit = 8;/*   1R */
+
+               for (i = 0; i < limit; i++) {
+                       if (psta_ht->ht_cap.supp_mcs_set[i/8] & BIT(i%8))
+                               tx_ra_bitmap |= BIT(i+12);
+               }
+
+               /* max short GI rate */
+               shortGIrate = psta_ht->sgi;
+       }
+
+       if (pcur_network->Configuration.DSConfig > 14) {
+               /*  5G band */
+               if (tx_ra_bitmap & 0xffff000)
+                       sta_band |= WIRELESS_11_5N | WIRELESS_11A;
+               else
+                       sta_band |= WIRELESS_11A;
+       } else {
+               if (tx_ra_bitmap & 0xffff000)
+                       sta_band |= WIRELESS_11_24N | WIRELESS_11G | WIRELESS_11B;
+               else if (tx_ra_bitmap & 0xff0)
+                       sta_band |= WIRELESS_11G | WIRELESS_11B;
+               else
+                       sta_band |= WIRELESS_11B;
+       }
+
+       psta->wireless_mode = sta_band;
+
+       raid = networktype_to_raid(sta_band);
+       init_rate = get_highest_rate_idx(tx_ra_bitmap&0x0fffffff)&0x3f;
+
+       if (psta->aid < NUM_STA) {
+               u8 arg = 0;
+
+               arg = psta->mac_id&0x1f;
+
+               arg |= BIT(7);/* support entry 2~31 */
+
+               if (shortGIrate)
+                       arg |= BIT(5);
+
+               tx_ra_bitmap |= ((raid<<28)&0xf0000000);
+
+               DBG_88E("%s => mac_id:%d , raid:%d , bitmap = 0x%x, arg = 0x%x\n",
+                       __func__ , psta->mac_id, raid , tx_ra_bitmap, arg);
+
+               /* bitmap[0:27] = tx_rate_bitmap */
+               /* bitmap[28:31]= Rate Adaptive id */
+               /* arg[0:4] = macid */
+               /* arg[5] = Short GI */
+               rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, rssi_level);
+
+               if (shortGIrate)
+                       init_rate |= BIT(6);
+
+               /* set ra_id, init_rate */
+               psta->raid = raid;
+               psta->init_rate = init_rate;
+
+       } else {
+               DBG_88E("station aid %d exceed the max number\n", psta->aid);
+       }
+}
+
+static void update_bmc_sta(struct adapter *padapter)
+{
+       unsigned long   irqL;
+       u32 init_rate = 0;
+       unsigned char   network_type, raid;
+       int i, supportRateNum = 0;
+       unsigned int tx_ra_bitmap = 0;
+       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+       struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
+       struct sta_info *psta = rtw_get_bcmc_stainfo(padapter);
+
+       if (psta) {
+               psta->aid = 0;/* default set to 0 */
+               psta->mac_id = psta->aid + 1;
+
+               psta->qos_option = 0;
+               psta->htpriv.ht_option = false;
+
+               psta->ieee8021x_blocked = 0;
+
+               _rtw_memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
+
+               /* prepare for add_RATid */
+               supportRateNum = rtw_get_rateset_len((u8 *)&pcur_network->SupportedRates);
+               network_type = rtw_check_network_type((u8 *)&pcur_network->SupportedRates, supportRateNum, 1);
+
+               memcpy(psta->bssrateset, &pcur_network->SupportedRates, supportRateNum);
+               psta->bssratelen = supportRateNum;
+
+               /* b/g mode ra_bitmap */
+               for (i = 0; i < supportRateNum; i++) {
+                       if (psta->bssrateset[i])
+                               tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i]&0x7f);
+               }
+
+               if (pcur_network->Configuration.DSConfig > 14) {
+                       /* force to A mode. 5G doesn't support CCK rates */
+                       network_type = WIRELESS_11A;
+                       tx_ra_bitmap = 0x150; /*  6, 12, 24 Mbps */
+               } else {
+                       /* force to b mode */
+                       network_type = WIRELESS_11B;
+                       tx_ra_bitmap = 0xf;
+               }
+
+               raid = networktype_to_raid(network_type);
+               init_rate = get_highest_rate_idx(tx_ra_bitmap&0x0fffffff)&0x3f;
+
+               /* ap mode */
+               rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true);
+
+               {
+                       u8 arg = 0;
+
+                       arg = psta->mac_id&0x1f;
+                       arg |= BIT(7);
+                       tx_ra_bitmap |= ((raid<<28)&0xf0000000);
+                       DBG_88E("update_bmc_sta, mask = 0x%x, arg = 0x%x\n", tx_ra_bitmap, arg);
+
+                       /* bitmap[0:27] = tx_rate_bitmap */
+                       /* bitmap[28:31]= Rate Adaptive id */
+                       /* arg[0:4] = macid */
+                       /* arg[5] = Short GI */
+                       rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, 0);
+               }
+               /* set ra_id, init_rate */
+               psta->raid = raid;
+               psta->init_rate = init_rate;
+
+               rtw_stassoc_hw_rpt(padapter, psta);
+
+               _enter_critical_bh(&psta->lock, &irqL);
+               psta->state = _FW_LINKED;
+               _exit_critical_bh(&psta->lock, &irqL);
+
+       } else {
+               DBG_88E("add_RATid_bmc_sta error!\n");
+       }
+}
+
+/* notes: */
+/* AID: 1~MAX for sta and 0 for bc/mc in ap/adhoc mode */
+/* MAC_ID = AID+1 for sta in ap/adhoc mode */
+/* MAC_ID = 1 for bc/mc for sta/ap/adhoc */
+/* MAC_ID = 0 for bssid for sta/ap/adhoc */
+/* CAM_ID = 0~3 for default key, cmd_id = macid + 3, macid = aid+1; */
+
+void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta)
+{
+       unsigned long   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;
+
+       psta->mac_id = psta->aid+1;
+       DBG_88E("%s\n", __func__);
+
+       /* ap mode */
+       rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true);
+
+       if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)
+               psta->ieee8021x_blocked = true;
+       else
+               psta->ieee8021x_blocked = false;
+
+
+       /* update sta's cap */
+
+       /* ERP */
+       VCS_update(padapter, psta);
+       /* HT related cap */
+       if (phtpriv_sta->ht_option) {
+               /* check if sta supports rx ampdu */
+               phtpriv_sta->ampdu_enable = phtpriv_ap->ampdu_enable;
+
+               /* check if sta support s Short GI */
+               if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40))
+                       phtpriv_sta->sgi = true;
+
+               /*  bwmode */
+               if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & IEEE80211_HT_CAP_SUP_WIDTH) {
+                       phtpriv_sta->bwmode = pmlmeext->cur_bwmode;
+                       phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset;
+               }
+               psta->qos_option = true;
+       } else {
+               phtpriv_sta->ampdu_enable = false;
+               phtpriv_sta->sgi = false;
+               phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_20;
+               phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+       }
+
+       /* Rx AMPDU */
+       send_delba(padapter, 0, psta->hwaddr);/*  recipient */
+
+       /* TX AMPDU */
+       send_delba(padapter, 1, psta->hwaddr);/* originator */
+       phtpriv_sta->agg_enable_bitmap = 0x0;/* reset */
+       phtpriv_sta->candidate_tid_bitmap = 0x0;/* reset */
+
+       /* todo: init other variables */
+
+       _rtw_memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
+
+       _enter_critical_bh(&psta->lock, &irqL);
+       psta->state |= _FW_LINKED;
+       _exit_critical_bh(&psta->lock, &irqL);
+}
+
+static void update_hw_ht_param(struct adapter *padapter)
+{
+       unsigned char           max_AMPDU_len;
+       unsigned char           min_MPDU_spacing;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info    *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+       DBG_88E("%s\n", __func__);
+
+       /* handle A-MPDU parameter field */
+       /*
+               AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k
+               AMPDU_para [4:2]:Min MPDU Start Spacing
+       */
+       max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03;
+
+       min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2;
+
+       rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing));
+
+       rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len));
+
+       /*  */
+       /*  Config SM Power Save setting */
+       /*  */
+       pmlmeinfo->SM_PS = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & 0x0C) >> 2;
+       if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC)
+               DBG_88E("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__);
+}
+
+static void start_bss_network(struct adapter *padapter, u8 *pbuf)
+{
+       u8 *p;
+       u8 val8, cur_channel, cur_bwmode, cur_ch_offset;
+       u16 bcn_interval;
+       u32     acparm;
+       int     ie_len;
+       struct registry_priv     *pregpriv = &padapter->registrypriv;
+       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+       struct security_priv *psecuritypriv = &(padapter->securitypriv);
+       struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
+       struct mlme_ext_priv    *pmlmeext = &(padapter->mlmeextpriv);
+       struct mlme_ext_info    *pmlmeinfo = &(pmlmeext->mlmext_info);
+       struct wlan_bssid_ex *pnetwork_mlmeext = &(pmlmeinfo->network);
+       struct HT_info_element *pht_info = NULL;
+#ifdef CONFIG_88EU_P2P
+       struct wifidirect_info  *pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+       bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod;
+       cur_channel = pnetwork->Configuration.DSConfig;
+       cur_bwmode = HT_CHANNEL_WIDTH_20;
+       cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+
+       /* check if there is wps ie, */
+       /* if there is wpsie in beacon, the hostapd will update beacon twice when stating hostapd, */
+       /* and at first time the security ie (RSN/WPA IE) will not include in beacon. */
+       if (!rtw_get_wps_ie(pnetwork->IEs+_FIXED_IE_LENGTH_, pnetwork->IELength-_FIXED_IE_LENGTH_, NULL, NULL))
+               pmlmeext->bstart_bss = true;
+
+       /* todo: update wmm, ht cap */
+       if (pmlmepriv->qospriv.qos_option)
+               pmlmeinfo->WMM_enable = true;
+       if (pmlmepriv->htpriv.ht_option) {
+               pmlmeinfo->WMM_enable = true;
+               pmlmeinfo->HT_enable = true;
+
+               update_hw_ht_param(padapter);
+       }
+
+       if (pmlmepriv->cur_network.join_res != true) { /* setting only at  first time */
+               /* WEP Key will be set before this function, do not clear CAM. */
+               if ((psecuritypriv->dot11PrivacyAlgrthm != _WEP40_) &&
+                   (psecuritypriv->dot11PrivacyAlgrthm != _WEP104_))
+                       flush_all_cam_entry(padapter);  /* clear CAM */
+       }
+
+       /* set MSR to AP_Mode */
+       Set_MSR(padapter, _HW_STATE_AP_);
+
+       /* Set BSSID REG */
+       rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pnetwork->MacAddress);
+
+       /* Set EDCA param reg */
+       acparm = 0x002F3217; /*  VO */
+       rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm));
+       acparm = 0x005E4317; /*  VI */
+       rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm));
+       acparm = 0x005ea42b;
+       rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm));
+       acparm = 0x0000A444; /*  BK */
+       rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm));
+
+       /* Set Security */
+       val8 = (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf;
+       rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+       /* Beacon Control related register */
+       rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&bcn_interval));
+
+       UpdateBrateTbl(padapter, pnetwork->SupportedRates);
+       rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates);
+
+       if (!pmlmepriv->cur_network.join_res) { /* setting only at  first time */
+               /* turn on all dynamic functions */
+               Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true);
+       }
+       /* set channel, bwmode */
+       p = rtw_get_ie((pnetwork->IEs + sizeof(struct ndis_802_11_fixed_ie)), _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - sizeof(struct ndis_802_11_fixed_ie)));
+       if (p && ie_len) {
+               pht_info = (struct HT_info_element *)(p+2);
+
+               if ((pregpriv->cbw40_enable) &&  (pht_info->infos[0] & BIT(2))) {
+                       /* switch to the 40M Hz mode */
+                       cur_bwmode = HT_CHANNEL_WIDTH_40;
+                       switch (pht_info->infos[0] & 0x3) {
+                       case 1:
+                               cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+                               break;
+                       case 3:
+                               cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+                               break;
+                       default:
+                               cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+                               break;
+                       }
+               }
+       }
+       /* TODO: need to judge the phy parameters on concurrent mode for single phy */
+       set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode);
+
+       DBG_88E("CH =%d, BW =%d, offset =%d\n", cur_channel, cur_bwmode, cur_ch_offset);
+
+       /*  */
+       pmlmeext->cur_channel = cur_channel;
+       pmlmeext->cur_bwmode = cur_bwmode;
+       pmlmeext->cur_ch_offset = cur_ch_offset;
+       pmlmeext->cur_wireless_mode = pmlmepriv->cur_network.network_type;
+
+       /* update cur_wireless_mode */
+       update_wireless_mode(padapter);
+
+       /* udpate capability after cur_wireless_mode updated */
+       update_capinfo(padapter, rtw_get_capability((struct wlan_bssid_ex *)pnetwork));
+
+       /* let pnetwork_mlmeext == pnetwork_mlme. */
+       memcpy(pnetwork_mlmeext, pnetwork, pnetwork->Length);
+
+#ifdef CONFIG_88EU_P2P
+       memcpy(pwdinfo->p2p_group_ssid, pnetwork->Ssid.Ssid, pnetwork->Ssid.SsidLength);
+       pwdinfo->p2p_group_ssid_len = pnetwork->Ssid.SsidLength;
+#endif /* CONFIG_88EU_P2P */
+
+       if (pmlmeext->bstart_bss) {
+               update_beacon(padapter, _TIM_IE_, NULL, false);
+
+               /* issue beacon frame */
+               if (send_beacon(padapter) == _FAIL)
+                       DBG_88E("issue_beacon, fail!\n");
+       }
+
+       /* update bc/mc sta_info */
+       update_bmc_sta(padapter);
+}
+
+int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf,  int len)
+{
+       int ret = _SUCCESS;
+       u8 *p;
+       u8 *pHT_caps_ie = NULL;
+       u8 *pHT_info_ie = NULL;
+       struct sta_info *psta = NULL;
+       u16 cap, ht_cap = false;
+       uint ie_len = 0;
+       int group_cipher, pairwise_cipher;
+       u8      channel, network_type, supportRate[NDIS_802_11_LENGTH_RATES_EX];
+       int supportRateNum = 0;
+       u8 OUI1[] = {0x00, 0x50, 0xf2, 0x01};
+       u8 WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
+       struct registry_priv *pregistrypriv = &padapter->registrypriv;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+       struct wlan_bssid_ex *pbss_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
+       u8 *ie = pbss_network->IEs;
+
+       /* SSID */
+       /* Supported rates */
+       /* DS Params */
+       /* WLAN_EID_COUNTRY */
+       /* ERP Information element */
+       /* Extended supported rates */
+       /* WPA/WPA2 */
+       /* Wi-Fi Wireless Multimedia Extensions */
+       /* ht_capab, ht_oper */
+       /* WPS IE */
+
+       DBG_88E("%s, len =%d\n", __func__, len);
+
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+               return _FAIL;
+
+
+       if (len > MAX_IE_SZ)
+               return _FAIL;
+
+       pbss_network->IELength = len;
+
+       _rtw_memset(ie, 0, MAX_IE_SZ);
+
+       memcpy(ie, pbuf, pbss_network->IELength);
+
+
+       if (pbss_network->InfrastructureMode != Ndis802_11APMode)
+               return _FAIL;
+
+       pbss_network->Rssi = 0;
+
+       memcpy(pbss_network->MacAddress, myid(&(padapter->eeprompriv)), ETH_ALEN);
+
+       /* beacon interval */
+       p = rtw_get_beacon_interval_from_ie(ie);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */
+       pbss_network->Configuration.BeaconPeriod = RTW_GET_LE16(p);
+
+       /* capability */
+       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(struct ndis_802_11_ssid));
+               memcpy(pbss_network->Ssid.Ssid, (p + 2), ie_len);
+               pbss_network->Ssid.SsidLength = ie_len;
+       }
+
+       /* channel */
+       channel = 0;
+       pbss_network->Configuration.Length = 0;
+       p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _DSSET_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+       if (p && ie_len > 0)
+               channel = *(p + 2);
+
+       pbss_network->Configuration.DSConfig = channel;
+
+       _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) {
+               memcpy(supportRate, p+2, ie_len);
+               supportRateNum = ie_len;
+       }
+
+       /* get ext_supported rates */
+       p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ie_len, pbss_network->IELength - _BEACON_IE_OFFSET_);
+       if (p !=  NULL) {
+               memcpy(supportRate+supportRateNum, p+2, ie_len);
+               supportRateNum += ie_len;
+       }
+
+       network_type = rtw_check_network_type(supportRate, supportRateNum, channel);
+
+       rtw_set_supported_rate(pbss_network->SupportedRates, network_type);
+
+       /* parsing ERP_IE */
+       p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+       if (p && ie_len > 0)
+               ERP_IE_handler(padapter, (struct ndis_802_11_var_ie *)p);
+
+       /* update privacy/security */
+       if (cap & BIT(4))
+               pbss_network->Privacy = 1;
+       else
+               pbss_network->Privacy = 0;
+
+       psecuritypriv->wpa_psk = 0;
+
+       /* wpa2 */
+       group_cipher = 0;
+       pairwise_cipher = 0;
+       psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_;
+       psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_;
+       p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+       if (p && ie_len > 0) {
+               if (rtw_parse_wpa2_ie(p, ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+                       psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+
+                       psecuritypriv->dot8021xalg = 1;/* psk,  todo:802.1x */
+                       psecuritypriv->wpa_psk |= BIT(1);
+
+                       psecuritypriv->wpa2_group_cipher = group_cipher;
+                       psecuritypriv->wpa2_pairwise_cipher = pairwise_cipher;
+               }
+       }
+       /* wpa */
+       ie_len = 0;
+       group_cipher = 0;
+       pairwise_cipher = 0;
+       psecuritypriv->wpa_group_cipher = _NO_PRIVACY_;
+       psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_;
+       for (p = ie + _BEACON_IE_OFFSET_;; p += (ie_len + 2)) {
+               p = rtw_get_ie(p, _SSN_IE_1_, &ie_len,
+                              (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));
+               if ((p) && (_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;
+               struct rtw_ieee80211_ht_cap *pht_cap = (struct rtw_ieee80211_ht_cap *)(p+2);
+
+               pHT_caps_ie = p;
+               ht_cap = true;
+               network_type |= WIRELESS_11_24N;
+
+               rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+               if ((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) ||
+                   (psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP))
+                       pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&(0x07<<2));
+               else
+                       pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&0x00);
+
+               /* set  Max Rx AMPDU size  to 64K */
+               pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_FACTOR & 0x03);
+
+               if (rf_type == RF_1T1R) {
+                       pht_cap->supp_mcs_set[0] = 0xff;
+                       pht_cap->supp_mcs_set[1] = 0x0;
+               }
+               memcpy(&pmlmepriv->htpriv.ht_cap, p+2, ie_len);
+       }
+
+       /* parsing HT_INFO_IE */
+       p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len,
+                      (pbss_network->IELength - _BEACON_IE_OFFSET_));
+       if (p && ie_len > 0)
+               pHT_info_ie = p;
+       switch (network_type) {
+       case WIRELESS_11B:
+               pbss_network->NetworkTypeInUse = Ndis802_11DS;
+               break;
+       case WIRELESS_11G:
+       case WIRELESS_11BG:
+       case WIRELESS_11G_24N:
+       case WIRELESS_11BG_24N:
+               pbss_network->NetworkTypeInUse = Ndis802_11OFDM24;
+               break;
+       case WIRELESS_11A:
+               pbss_network->NetworkTypeInUse = Ndis802_11OFDM5;
+               break;
+       default:
+               pbss_network->NetworkTypeInUse = Ndis802_11OFDM24;
+               break;
+       }
+
+       pmlmepriv->cur_network.network_type = network_type;
+
+       pmlmepriv->htpriv.ht_option = false;
+
+       if ((psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_TKIP) ||
+           (psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_TKIP)) {
+               /* todo: */
+               /* ht_cap = false; */
+       }
+
+       /* ht_cap */
+       if (pregistrypriv->ht_enable && ht_cap) {
+               pmlmepriv->htpriv.ht_option = true;
+               pmlmepriv->qospriv.qos_option = 1;
+
+               if (pregistrypriv->ampdu_enable == 1)
+                       pmlmepriv->htpriv.ampdu_enable = true;
+               HT_caps_handler(padapter, (struct ndis_802_11_var_ie *)pHT_caps_ie);
+
+               HT_info_handler(padapter, (struct ndis_802_11_var_ie *)pHT_info_ie);
+       }
+
+       pbss_network->Length = get_wlan_bssid_ex_sz((struct wlan_bssid_ex  *)pbss_network);
+
+       /* issue beacon to start bss network */
+       start_bss_network(padapter, (u8 *)pbss_network);
+
+       /* alloc sta_info for ap itself */
+       psta = rtw_get_stainfo(&padapter->stapriv, pbss_network->MacAddress);
+       if (!psta) {
+               psta = rtw_alloc_stainfo(&padapter->stapriv, pbss_network->MacAddress);
+               if (psta == NULL)
+                       return _FAIL;
+       }
+
+       pmlmepriv->cur_network.join_res = true;/* for check if already set beacon */
+       return ret;
+}
+
+void rtw_set_macaddr_acl(struct adapter *padapter, int mode)
+{
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+
+       DBG_88E("%s, mode =%d\n", __func__, mode);
+
+       pacl_list->mode = mode;
+}
+
+int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
+{
+       unsigned long irqL;
+       struct list_head *plist, *phead;
+       u8 added = false;
+       int i, ret = 0;
+       struct rtw_wlan_acl_node *paclnode;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+       struct __queue *pacl_node_q = &pacl_list->acl_node_q;
+
+       DBG_88E("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, (addr));
+
+       if ((NUM_ACL-1) < pacl_list->num)
+               return -1;
+
+       _enter_critical_bh(&(pacl_node_q->lock), &irqL);
+
+       phead = get_list_head(pacl_node_q);
+       plist = get_next(phead);
+
+       while (!rtw_end_of_queue_search(phead, plist)) {
+               paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
+               plist = get_next(plist);
+
+               if (_rtw_memcmp(paclnode->addr, addr, ETH_ALEN)) {
+                       if (paclnode->valid) {
+                               added = true;
+                               DBG_88E("%s, sta has been added\n", __func__);
+                               break;
+                       }
+               }
+       }
+
+       _exit_critical_bh(&(pacl_node_q->lock), &irqL);
+
+       if (added)
+               return ret;
+
+       _enter_critical_bh(&(pacl_node_q->lock), &irqL);
+
+       for (i = 0; i < NUM_ACL; i++) {
+               paclnode = &pacl_list->aclnode[i];
+
+               if (!paclnode->valid) {
+                       _rtw_init_listhead(&paclnode->list);
+
+                       memcpy(paclnode->addr, addr, ETH_ALEN);
+
+                       paclnode->valid = true;
+
+                       rtw_list_insert_tail(&paclnode->list, get_list_head(pacl_node_q));
+
+                       pacl_list->num++;
+
+                       break;
+               }
+       }
+
+       DBG_88E("%s, acl_num =%d\n", __func__, pacl_list->num);
+
+       _exit_critical_bh(&(pacl_node_q->lock), &irqL);
+
+       return ret;
+}
+
+int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
+{
+       unsigned long irqL;
+       struct list_head *plist, *phead;
+       int ret = 0;
+       struct rtw_wlan_acl_node *paclnode;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+       struct __queue *pacl_node_q = &pacl_list->acl_node_q;
+
+       DBG_88E("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, (addr));
+
+       _enter_critical_bh(&(pacl_node_q->lock), &irqL);
+
+       phead = get_list_head(pacl_node_q);
+       plist = get_next(phead);
+
+       while (!rtw_end_of_queue_search(phead, plist)) {
+               paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
+               plist = get_next(plist);
+
+               if (_rtw_memcmp(paclnode->addr, addr, ETH_ALEN)) {
+                       if (paclnode->valid) {
+                               paclnode->valid = false;
+
+                               rtw_list_delete(&paclnode->list);
+
+                               pacl_list->num--;
+                       }
+               }
+       }
+
+       _exit_critical_bh(&(pacl_node_q->lock), &irqL);
+
+       DBG_88E("%s, acl_num =%d\n", __func__, pacl_list->num);
+       return ret;
+}
+
+static void update_bcn_fixed_ie(struct adapter *padapter)
+{
+       DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_erpinfo_ie(struct adapter *padapter)
+{
+       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+       struct mlme_ext_priv    *pmlmeext = &(padapter->mlmeextpriv);
+       struct mlme_ext_info    *pmlmeinfo = &(pmlmeext->mlmext_info);
+       struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
+       unsigned char *p, *ie = pnetwork->IEs;
+       u32 len = 0;
+
+       DBG_88E("%s, ERP_enable =%d\n", __func__, pmlmeinfo->ERP_enable);
+
+       if (!pmlmeinfo->ERP_enable)
+               return;
+
+       /* parsing ERP_IE */
+       p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &len,
+                      (pnetwork->IELength - _BEACON_IE_OFFSET_));
+       if (p && len > 0) {
+               struct ndis_802_11_var_ie *pIE = (struct ndis_802_11_var_ie *)p;
+
+               if (pmlmepriv->num_sta_non_erp == 1)
+                       pIE->data[0] |= RTW_ERP_INFO_NON_ERP_PRESENT|RTW_ERP_INFO_USE_PROTECTION;
+               else
+                       pIE->data[0] &= ~(RTW_ERP_INFO_NON_ERP_PRESENT|RTW_ERP_INFO_USE_PROTECTION);
+
+               if (pmlmepriv->num_sta_no_short_preamble > 0)
+                       pIE->data[0] |= RTW_ERP_INFO_BARKER_PREAMBLE_MODE;
+               else
+                       pIE->data[0] &= ~(RTW_ERP_INFO_BARKER_PREAMBLE_MODE);
+
+               ERP_IE_handler(padapter, pIE);
+       }
+}
+
+static void update_bcn_htcap_ie(struct adapter *padapter)
+{
+       DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_htinfo_ie(struct adapter *padapter)
+{
+       DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_rsn_ie(struct adapter *padapter)
+{
+       DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_wpa_ie(struct adapter *padapter)
+{
+       DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_wmm_ie(struct adapter *padapter)
+{
+       DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_wps_ie(struct adapter *padapter)
+{
+       u8 *pwps_ie = NULL, *pwps_ie_src;
+       u8 *premainder_ie, *pbackup_remainder_ie = NULL;
+       uint wps_ielen = 0, wps_offset, remainder_ielen;
+       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+       struct mlme_ext_priv    *pmlmeext = &(padapter->mlmeextpriv);
+       struct mlme_ext_info    *pmlmeinfo = &(pmlmeext->mlmext_info);
+       struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
+       unsigned char *ie = pnetwork->IEs;
+       u32 ielen = pnetwork->IELength;
+
+       DBG_88E("%s\n", __func__);
+
+       pwps_ie = rtw_get_wps_ie(ie+_FIXED_IE_LENGTH_, ielen-_FIXED_IE_LENGTH_, NULL, &wps_ielen);
+
+       if (pwps_ie == NULL || wps_ielen == 0)
+               return;
+
+       wps_offset = (uint)(pwps_ie-ie);
+
+       premainder_ie = pwps_ie + wps_ielen;
+
+       remainder_ielen = ielen - wps_offset - wps_ielen;
+
+       if (remainder_ielen > 0) {
+               pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+               if (pbackup_remainder_ie)
+                       memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+       }
+
+       pwps_ie_src = pmlmepriv->wps_beacon_ie;
+       if (pwps_ie_src == NULL)
+               return;
+
+       wps_ielen = (uint)pwps_ie_src[1];/* to get ie data len */
+       if ((wps_offset+wps_ielen+2+remainder_ielen) <= MAX_IE_SZ) {
+               memcpy(pwps_ie, pwps_ie_src, wps_ielen+2);
+               pwps_ie += (wps_ielen+2);
+
+               if (pbackup_remainder_ie)
+                       memcpy(pwps_ie, pbackup_remainder_ie, remainder_ielen);
+
+               /* update IELength */
+               pnetwork->IELength = wps_offset + (wps_ielen+2) + remainder_ielen;
+       }
+
+       if (pbackup_remainder_ie)
+               kfree(pbackup_remainder_ie);
+}
+
+static void update_bcn_p2p_ie(struct adapter *padapter)
+{
+}
+
+static void update_bcn_vendor_spec_ie(struct adapter *padapter, u8 *oui)
+{
+       DBG_88E("%s\n", __func__);
+
+       if (_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
+               DBG_88E("unknown OUI type!\n");
+}
+
+void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx)
+{
+       unsigned long irqL;
+       struct mlme_priv *pmlmepriv;
+       struct mlme_ext_priv    *pmlmeext;
+
+       if (!padapter)
+               return;
+
+       pmlmepriv = &(padapter->mlmepriv);
+       pmlmeext = &(padapter->mlmeextpriv);
+
+       if (!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 _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);
+
+       if (tx)
+               set_tx_beacon_cmd(padapter);
+}
+
+/*
+op_mode
+Set to 0 (HT pure) under the followign conditions
+       - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
+       - all STAs in the BSS are 20 MHz HT in 20 MHz BSS
+Set to 1 (HT non-member protection) if there may be non-HT STAs
+       in both the primary and the secondary channel
+Set to 2 if only HT STAs are associated in BSS,
+       however and at least one 20 MHz HT STA is associated
+Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
+       (currently non-GF HT station is considered as non-HT STA also)
+*/
+static int rtw_ht_operation_update(struct adapter *padapter)
+{
+       u16 cur_op_mode, new_op_mode;
+       int op_mode_changes = 0;
+       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+       struct ht_priv  *phtpriv_ap = &pmlmepriv->htpriv;
+
+       if (pmlmepriv->htpriv.ht_option)
+               return 0;
+
+       DBG_88E("%s current operation mode = 0x%X\n",
+               __func__, pmlmepriv->ht_op_mode);
+
+       if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
+           pmlmepriv->num_sta_ht_no_gf) {
+               pmlmepriv->ht_op_mode |=
+                       HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+               op_mode_changes++;
+       } else if ((pmlmepriv->ht_op_mode &
+                  HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
+                  pmlmepriv->num_sta_ht_no_gf == 0) {
+               pmlmepriv->ht_op_mode &=
+                       ~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+               op_mode_changes++;
+       }
+
+       if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+           (pmlmepriv->num_sta_no_ht || pmlmepriv->olbc_ht)) {
+               pmlmepriv->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+               op_mode_changes++;
+       } else if ((pmlmepriv->ht_op_mode &
+                   HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+                  (pmlmepriv->num_sta_no_ht == 0 && !pmlmepriv->olbc_ht)) {
+               pmlmepriv->ht_op_mode &=
+                       ~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+               op_mode_changes++;
+       }
+
+       /* Note: currently we switch to the MIXED op mode if HT non-greenfield
+        * station is associated. Probably it's a theoretical case, since
+        * it looks like all known HT STAs support greenfield.
+        */
+       new_op_mode = 0;
+       if (pmlmepriv->num_sta_no_ht ||
+           (pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT))
+               new_op_mode = OP_MODE_MIXED;
+       else if ((phtpriv_ap->ht_cap.cap_info & IEEE80211_HT_CAP_SUP_WIDTH) &&
+                pmlmepriv->num_sta_ht_20mhz)
+               new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
+       else if (pmlmepriv->olbc_ht)
+               new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
+       else
+               new_op_mode = OP_MODE_PURE;
+
+       cur_op_mode = pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+       if (cur_op_mode != new_op_mode) {
+               pmlmepriv->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+               pmlmepriv->ht_op_mode |= new_op_mode;
+               op_mode_changes++;
+       }
+
+       DBG_88E("%s new operation mode = 0x%X changes =%d\n",
+               __func__, pmlmepriv->ht_op_mode, op_mode_changes);
+
+       return op_mode_changes;
+}
+
+void associated_clients_update(struct adapter *padapter, u8 updated)
+{
+       /* update associcated stations cap. */
+       if (updated) {
+               unsigned long irqL;
+               struct list_head *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);
+
+                       VCS_update(padapter, psta);
+               }
+               _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+       }
+}
+
+/* called > TSR LEVEL for USB or SDIO Interface*/
+void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta)
+{
+       u8 beacon_updated = false;
+       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+       struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+
+       if (!(psta->flags & WLAN_STA_SHORT_PREAMBLE)) {
+               if (!psta->no_short_preamble_set) {
+                       psta->no_short_preamble_set = 1;
+
+                       pmlmepriv->num_sta_no_short_preamble++;
+
+                       if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+                           (pmlmepriv->num_sta_no_short_preamble == 1)) {
+                               beacon_updated = true;
+                               update_beacon(padapter, 0xFF, NULL, true);
+                       }
+               }
+       } else {
+               if (psta->no_short_preamble_set) {
+                       psta->no_short_preamble_set = 0;
+
+                       pmlmepriv->num_sta_no_short_preamble--;
+
+                       if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+                           (pmlmepriv->num_sta_no_short_preamble == 0)) {
+                               beacon_updated = true;
+                               update_beacon(padapter, 0xFF, NULL, true);
+                       }
+               }
+       }
+
+       if (psta->flags & WLAN_STA_NONERP) {
+               if (!psta->nonerp_set) {
+                       psta->nonerp_set = 1;
+
+                       pmlmepriv->num_sta_non_erp++;
+
+                       if (pmlmepriv->num_sta_non_erp == 1) {
+                               beacon_updated = true;
+                               update_beacon(padapter, _ERPINFO_IE_, NULL, true);
+                       }
+               }
+       } else {
+               if (psta->nonerp_set) {
+                       psta->nonerp_set = 0;
+
+                       pmlmepriv->num_sta_non_erp--;
+
+                       if (pmlmepriv->num_sta_non_erp == 0) {
+                               beacon_updated = true;
+                               update_beacon(padapter, _ERPINFO_IE_, NULL, true);
+                       }
+               }
+       }
+
+       if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT)) {
+               if (!psta->no_short_slot_time_set) {
+                       psta->no_short_slot_time_set = 1;
+
+                       pmlmepriv->num_sta_no_short_slot_time++;
+
+                       if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+                           (pmlmepriv->num_sta_no_short_slot_time == 1)) {
+                               beacon_updated = true;
+                               update_beacon(padapter, 0xFF, NULL, true);
+                       }
+               }
+       } else {
+               if (psta->no_short_slot_time_set) {
+                       psta->no_short_slot_time_set = 0;
+
+                       pmlmepriv->num_sta_no_short_slot_time--;
+
+                       if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+                           (pmlmepriv->num_sta_no_short_slot_time == 0)) {
+                               beacon_updated = true;
+                               update_beacon(padapter, 0xFF, NULL, true);
+                       }
+               }
+       }
+
+       if (psta->flags & WLAN_STA_HT) {
+               u16 ht_capab = psta->htpriv.ht_cap.cap_info;
+
+               DBG_88E("HT: STA %pM HT Capabilities Info: 0x%04x\n",
+                       (psta->hwaddr), ht_capab);
+
+               if (psta->no_ht_set) {
+                       psta->no_ht_set = 0;
+                       pmlmepriv->num_sta_no_ht--;
+               }
+
+               if ((ht_capab & IEEE80211_HT_CAP_GRN_FLD) == 0) {
+                       if (!psta->no_ht_gf_set) {
+                               psta->no_ht_gf_set = 1;
+                               pmlmepriv->num_sta_ht_no_gf++;
+                       }
+                       DBG_88E("%s STA %pM - no greenfield, num of non-gf stations %d\n",
+                                  __func__, (psta->hwaddr),
+                                  pmlmepriv->num_sta_ht_no_gf);
+               }
+
+               if ((ht_capab & IEEE80211_HT_CAP_SUP_WIDTH) == 0) {
+                       if (!psta->ht_20mhz_set) {
+                               psta->ht_20mhz_set = 1;
+                               pmlmepriv->num_sta_ht_20mhz++;
+                       }
+                       DBG_88E("%s STA %pM - 20 MHz HT, num of 20MHz HT STAs %d\n",
+                                  __func__, (psta->hwaddr),
+                                  pmlmepriv->num_sta_ht_20mhz);
+               }
+       } else {
+               if (!psta->no_ht_set) {
+                       psta->no_ht_set = 1;
+                       pmlmepriv->num_sta_no_ht++;
+               }
+               if (pmlmepriv->htpriv.ht_option) {
+                       DBG_88E("%s STA %pM - no HT, num of non-HT stations %d\n",
+                               __func__, (psta->hwaddr),
+                               pmlmepriv->num_sta_no_ht);
+               }
+       }
+
+       if (rtw_ht_operation_update(padapter) > 0) {
+               update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, false);
+               update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true);
+       }
+
+       /* update associcated stations cap. */
+       associated_clients_update(padapter,  beacon_updated);
+
+       DBG_88E("%s, updated =%d\n", __func__, beacon_updated);
+}
+
+u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta)
+{
+       u8 beacon_updated = false;
+       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+       struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+
+       if (!psta)
+               return beacon_updated;
+
+       if (psta->no_short_preamble_set) {
+               psta->no_short_preamble_set = 0;
+               pmlmepriv->num_sta_no_short_preamble--;
+               if (pmlmeext->cur_wireless_mode > WIRELESS_11B &&
+                   pmlmepriv->num_sta_no_short_preamble == 0) {
+                       beacon_updated = true;
+                       update_beacon(padapter, 0xFF, NULL, true);
+               }
+       }
+
+       if (psta->nonerp_set) {
+               psta->nonerp_set = 0;
+               pmlmepriv->num_sta_non_erp--;
+               if (pmlmepriv->num_sta_non_erp == 0) {
+                       beacon_updated = true;
+                       update_beacon(padapter, _ERPINFO_IE_, NULL, true);
+               }
+       }
+
+       if (psta->no_short_slot_time_set) {
+               psta->no_short_slot_time_set = 0;
+               pmlmepriv->num_sta_no_short_slot_time--;
+               if (pmlmeext->cur_wireless_mode > WIRELESS_11B &&
+                   pmlmepriv->num_sta_no_short_slot_time == 0) {
+                       beacon_updated = true;
+                       update_beacon(padapter, 0xFF, NULL, true);
+               }
+       }
+
+       if (psta->no_ht_gf_set) {
+               psta->no_ht_gf_set = 0;
+               pmlmepriv->num_sta_ht_no_gf--;
+       }
+
+       if (psta->no_ht_set) {
+               psta->no_ht_set = 0;
+               pmlmepriv->num_sta_no_ht--;
+       }
+
+       if (psta->ht_20mhz_set) {
+               psta->ht_20mhz_set = 0;
+               pmlmepriv->num_sta_ht_20mhz--;
+       }
+
+       if (rtw_ht_operation_update(padapter) > 0) {
+               update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, false);
+               update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true);
+       }
+
+       /* update associcated stations cap. */
+
+       DBG_88E("%s, updated =%d\n", __func__, beacon_updated);
+
+       return beacon_updated;
+}
+
+u8 ap_free_sta(struct adapter *padapter, struct sta_info *psta,
+              bool active, u16 reason)
+{
+       unsigned long irqL;
+       u8 beacon_updated = false;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+
+       if (!psta)
+               return beacon_updated;
+
+       /* tear down Rx AMPDU */
+       send_delba(padapter, 0, psta->hwaddr);/*  recipient */
+
+       /* tear down TX AMPDU */
+       send_delba(padapter, 1, psta->hwaddr);/*  originator */
+       psta->htpriv.agg_enable_bitmap = 0x0;/* reset */
+       psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */
+
+       if (active)
+               issue_deauth(padapter, psta->hwaddr, reason);
+
+       /* clear cam entry / key */
+       rtw_clearstakey_cmd(padapter, (u8 *)psta, (u8)(psta->mac_id + 3), true);
+
+
+       _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);
+
+       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_ap_inform_ch_switch(struct adapter *padapter, u8 new_ch, u8 ch_offset)
+{
+       unsigned long irqL;
+       struct list_head *phead, *plist;
+       int ret = 0;
+       struct sta_info *psta = NULL;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info    *pmlmeinfo = &(pmlmeext->mlmext_info);
+       u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+       if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+               return ret;
+
+       DBG_88E(FUNC_NDEV_FMT" with ch:%u, offset:%u\n",
+               FUNC_NDEV_ARG(padapter->pnetdev), new_ch, ch_offset);
+
+       _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+       phead = &pstapriv->asoc_list;
+       plist = get_next(phead);
+
+       /* for each sta in asoc_queue */
+       while (!rtw_end_of_queue_search(phead, plist)) {
+               psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+               plist = get_next(plist);
+
+               issue_action_spct_ch_switch(padapter, psta->hwaddr, new_ch, ch_offset);
+               psta->expire_to = ((pstapriv->expire_to * 2) > 5) ? 5 : (pstapriv->expire_to * 2);
+       }
+       _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+       issue_action_spct_ch_switch(padapter, bc_addr, new_ch, ch_offset);
+
+       return ret;
+}
+
+int rtw_sta_flush(struct adapter *padapter)
+{
+       unsigned long irqL;
+       struct list_head *phead, *plist;
+       int ret = 0;
+       struct sta_info *psta = NULL;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info    *pmlmeinfo = &(pmlmeext->mlmext_info);
+       u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+       DBG_88E(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
+
+       if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+               return ret;
+
+       _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+       phead = &pstapriv->asoc_list;
+       plist = get_next(phead);
+
+       /* free 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);
+
+               rtw_list_delete(&psta->asoc_list);
+               pstapriv->asoc_list_cnt--;
+
+               ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
+       }
+       _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+
+       issue_deauth(padapter, bc_addr, WLAN_REASON_DEAUTH_LEAVING);
+
+       associated_clients_update(padapter, true);
+
+       return ret;
+}
+
+/* called > TSR LEVEL for USB or SDIO Interface*/
+void sta_info_update(struct adapter *padapter, struct sta_info *psta)
+{
+       int flags = psta->flags;
+       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+       /* update wmm cap. */
+       if (WLAN_STA_WME&flags)
+               psta->qos_option = 1;
+       else
+               psta->qos_option = 0;
+
+       if (pmlmepriv->qospriv.qos_option == 0)
+               psta->qos_option = 0;
+
+       /* update 802.11n ht cap. */
+       if (WLAN_STA_HT&flags) {
+               psta->htpriv.ht_option = true;
+               psta->qos_option = 1;
+       } else {
+               psta->htpriv.ht_option = false;
+       }
+
+       if (!pmlmepriv->htpriv.ht_option)
+               psta->htpriv.ht_option = false;
+
+       update_sta_info_apmode(padapter, psta);
+}
+
+/* called >= TSR LEVEL for USB or SDIO Interface*/
+void ap_sta_info_defer_update(struct adapter *padapter, struct sta_info *psta)
+{
+       if (psta->state & _FW_LINKED) {
+               /* add ratid */
+               add_RATid(padapter, psta, 0);/* DM_RATR_STA_INIT */
+       }
+}
+
+void start_ap_mode(struct adapter *padapter)
+{
+       int i;
+       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+
+       pmlmepriv->update_bcn = false;
+
+       pmlmeext->bstart_bss = false;
+
+       pmlmepriv->num_sta_non_erp = 0;
+
+       pmlmepriv->num_sta_no_short_slot_time = 0;
+
+       pmlmepriv->num_sta_no_short_preamble = 0;
+
+       pmlmepriv->num_sta_ht_no_gf = 0;
+       pmlmepriv->num_sta_no_ht = 0;
+       pmlmepriv->num_sta_ht_20mhz = 0;
+
+       pmlmepriv->olbc = false;
+
+       pmlmepriv->olbc_ht = false;
+
+       pmlmepriv->ht_op_mode = 0;
+
+       for (i = 0; i < NUM_STA; i++)
+               pstapriv->sta_aid[i] = NULL;
+
+       pmlmepriv->wps_beacon_ie = NULL;
+       pmlmepriv->wps_probe_resp_ie = NULL;
+       pmlmepriv->wps_assoc_resp_ie = NULL;
+
+       pmlmepriv->p2p_beacon_ie = NULL;
+       pmlmepriv->p2p_probe_resp_ie = NULL;
+
+       /* for ACL */
+       _rtw_init_listhead(&(pacl_list->acl_node_q.queue));
+       pacl_list->num = 0;
+       pacl_list->mode = 0;
+       for (i = 0; i < NUM_ACL; i++) {
+               _rtw_init_listhead(&pacl_list->aclnode[i].list);
+               pacl_list->aclnode[i].valid = false;
+       }
+}
+
+void stop_ap_mode(struct adapter *padapter)
+{
+       unsigned long irqL;
+       struct list_head *phead, *plist;
+       struct rtw_wlan_acl_node *paclnode;
+       struct sta_info *psta = NULL;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+       struct __queue *pacl_node_q = &pacl_list->acl_node_q;
+
+       pmlmepriv->update_bcn = false;
+       pmlmeext->bstart_bss = false;
+
+       /* reset and init security priv , this can refine with rtw_reset_securitypriv */
+       _rtw_memset((unsigned char *)&padapter->securitypriv, 0, sizeof(struct security_priv));
+       padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+       padapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
+
+       /* for ACL */
+       _enter_critical_bh(&(pacl_node_q->lock), &irqL);
+       phead = get_list_head(pacl_node_q);
+       plist = get_next(phead);
+       while ((rtw_end_of_queue_search(phead, plist)) == false) {
+               paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
+               plist = get_next(plist);
+
+               if (paclnode->valid) {
+                       paclnode->valid = false;
+
+                       rtw_list_delete(&paclnode->list);
+
+                       pacl_list->num--;
+               }
+       }
+       _exit_critical_bh(&(pacl_node_q->lock), &irqL);
+
+       DBG_88E("%s, free acl_node_queue, num =%d\n", __func__, pacl_list->num);
+
+       rtw_sta_flush(padapter);
+
+       /* free_assoc_sta_resources */
+       rtw_free_all_stainfo(padapter);
+
+       psta = rtw_get_bcmc_stainfo(padapter);
+       _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+       rtw_free_stainfo(padapter, psta);
+       _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+
+       rtw_init_bcmc_stainfo(padapter);
+
+       rtw_free_mlme_priv_ie_data(pmlmepriv);
+}
+
+#endif /* CONFIG_88EU_AP_MODE */
diff --git a/drivers/staging/rtl8188eu/core/rtw_br_ext.c b/drivers/staging/rtl8188eu/core/rtw_br_ext.c
new file mode 100644 (file)
index 0000000..fbca394
--- /dev/null
@@ -0,0 +1,1199 @@
+/******************************************************************************
+ *
+ * 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 "rtw_br_ext.h"
+#include <usb_osintf.h>
+#include <recv_osdep.h>
+
+#ifndef csum_ipv6_magic
+#include <net/ip6_checksum.h>
+#endif
+
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+#include <net/ndisc.h>
+#include <net/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 NULL;
+}
+
+
+static inline int __nat25_add_pppoe_tag(struct sk_buff *skb, struct pppoe_tag *tag)
+{
+       struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
+       int data_len;
+
+       data_len = tag->tag_len + TAG_HDR_LEN;
+       if (skb_tailroom(skb) < data_len) {
+               _DEBUG_ERR("skb_tailroom() failed in add SID tag!\n");
+               return -1;
+       }
+
+       skb_put(skb, data_len);
+       /*  have a room for new tag */
+       memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ntohs(ph->length));
+       ph->length = htons(ntohs(ph->length) + data_len);
+       memcpy((unsigned char *)ph->tag, tag, data_len);
+       return data_len;
+}
+
+static int skb_pull_and_merge(struct sk_buff *skb, unsigned char *src, int len)
+{
+       int tail_len;
+       unsigned long end, tail;
+
+       if ((src+len) > skb_tail_pointer(skb) || skb->len < len)
+               return -1;
+
+       tail = (unsigned long)skb_tail_pointer(skb);
+       end = (unsigned long)src+len;
+       if (tail < end)
+               return -1;
+
+       tail_len = (int)(tail-end);
+       if (tail_len > 0)
+               memmove(src, src+len, tail_len);
+
+       skb_trim(skb, skb->len-len);
+       return 0;
+}
+
+static inline unsigned long __nat25_timeout(struct adapter *priv)
+{
+       unsigned long timeout;
+
+       timeout = jiffies - NAT25_AGEING_TIME*HZ;
+
+       return timeout;
+}
+
+
+static inline int  __nat25_has_expired(struct adapter *priv,
+                               struct nat25_network_db_entry *fdb)
+{
+       if (time_before_eq(fdb->ageing_timer, __nat25_timeout(priv)))
+               return 1;
+
+       return 0;
+}
+
+
+static inline void __nat25_generate_ipv4_network_addr(unsigned char *networkAddr,
+                               unsigned int *ipAddr)
+{
+       memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+       networkAddr[0] = NAT25_IPV4;
+       memcpy(networkAddr+7, (unsigned char *)ipAddr, 4);
+}
+
+
+static inline void __nat25_generate_ipx_network_addr_with_node(unsigned char *networkAddr,
+                               unsigned int *ipxNetAddr, unsigned char *ipxNodeAddr)
+{
+       memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+       networkAddr[0] = NAT25_IPX;
+       memcpy(networkAddr+1, (unsigned char *)ipxNetAddr, 4);
+       memcpy(networkAddr+5, ipxNodeAddr, 6);
+}
+
+
+static inline void __nat25_generate_ipx_network_addr_with_socket(unsigned char *networkAddr,
+                               unsigned int *ipxNetAddr, unsigned short *ipxSocketAddr)
+{
+       memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+       networkAddr[0] = NAT25_IPX;
+       memcpy(networkAddr+1, (unsigned char *)ipxNetAddr, 4);
+       memcpy(networkAddr+5, (unsigned char *)ipxSocketAddr, 2);
+}
+
+
+static inline void __nat25_generate_apple_network_addr(unsigned char *networkAddr,
+                               unsigned short *network, unsigned char *node)
+{
+       memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+       networkAddr[0] = NAT25_APPLE;
+       memcpy(networkAddr+1, (unsigned char *)network, 2);
+       networkAddr[3] = *node;
+}
+
+static inline void __nat25_generate_pppoe_network_addr(unsigned char *networkAddr,
+                               unsigned char *ac_mac, unsigned short *sid)
+{
+       memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+       networkAddr[0] = NAT25_PPPOE;
+       memcpy(networkAddr+1, (unsigned char *)sid, 2);
+       memcpy(networkAddr+3, (unsigned char *)ac_mac, 6);
+}
+
+static  void __nat25_generate_ipv6_network_addr(unsigned char *networkAddr,
+                               unsigned int *ipAddr)
+{
+       memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+       networkAddr[0] = NAT25_IPV6;
+       memcpy(networkAddr+1, (unsigned char *)ipAddr, 16);
+}
+
+static unsigned char *scan_tlv(unsigned char *data, int len, unsigned char tag, unsigned char len8b)
+{
+       while (len > 0) {
+               if (*data == tag && *(data+1) == len8b && len >= len8b*8)
+                       return data+2;
+
+               len -= (*(data+1))*8;
+               data += (*(data+1))*8;
+       }
+       return NULL;
+}
+
+static int update_nd_link_layer_addr(unsigned char *data, int len, unsigned char *replace_mac)
+{
+       struct icmp6hdr *icmphdr = (struct icmp6hdr *)data;
+       unsigned char *mac;
+
+       if (icmphdr->icmp6_type == NDISC_ROUTER_SOLICITATION) {
+               if (len >= 8) {
+                       mac = scan_tlv(&data[8], len-8, 1, 1);
+                       if (mac) {
+                               _DEBUG_INFO("Router Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+                                       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+                                       replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+                               memcpy(mac, replace_mac, 6);
+                               return 1;
+                       }
+               }
+       } else if (icmphdr->icmp6_type == NDISC_ROUTER_ADVERTISEMENT) {
+               if (len >= 16) {
+                       mac = scan_tlv(&data[16], len-16, 1, 1);
+                       if (mac) {
+                               _DEBUG_INFO("Router Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+                                       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+                                       replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+                               memcpy(mac, replace_mac, 6);
+                               return 1;
+                       }
+               }
+       } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
+               if (len >= 24) {
+                       mac = scan_tlv(&data[24], len-24, 1, 1);
+                       if (mac) {
+                               _DEBUG_INFO("Neighbor Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+                                       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+                                       replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+                               memcpy(mac, replace_mac, 6);
+                               return 1;
+                       }
+               }
+       } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) {
+               if (len >= 24) {
+                       mac = scan_tlv(&data[24], len-24, 2, 1);
+                       if (mac) {
+                               _DEBUG_INFO("Neighbor Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+                                       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+                                       replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+                               memcpy(mac, replace_mac, 6);
+                               return 1;
+                       }
+               }
+       } else if (icmphdr->icmp6_type == NDISC_REDIRECT) {
+               if (len >= 40) {
+                       mac = scan_tlv(&data[40], len-40, 2, 1);
+                       if (mac) {
+                               _DEBUG_INFO("Redirect,  replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+                                       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+                                       replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+                               memcpy(mac, replace_mac, 6);
+                               return 1;
+                       }
+               }
+       }
+       return 0;
+}
+
+static inline int __nat25_network_hash(unsigned char *networkAddr)
+{
+       if (networkAddr[0] == NAT25_IPV4) {
+               unsigned long x;
+
+               x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
+
+               return x & (NAT25_HASH_SIZE - 1);
+       } else if (networkAddr[0] == NAT25_IPX) {
+               unsigned long x;
+
+               x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
+                       networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
+
+               return x & (NAT25_HASH_SIZE - 1);
+       } else if (networkAddr[0] == NAT25_APPLE) {
+               unsigned long x;
+
+               x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3];
+
+               return x & (NAT25_HASH_SIZE - 1);
+       } else if (networkAddr[0] == NAT25_PPPOE) {
+               unsigned long x;
+
+               x = networkAddr[0] ^ networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8];
+
+               return x & (NAT25_HASH_SIZE - 1);
+       } else if (networkAddr[0] == NAT25_IPV6) {
+               unsigned long x;
+
+               x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
+                       networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10] ^
+                       networkAddr[11] ^ networkAddr[12] ^ networkAddr[13] ^ networkAddr[14] ^ networkAddr[15] ^
+                       networkAddr[16];
+
+               return x & (NAT25_HASH_SIZE - 1);
+       } else {
+               unsigned long x = 0;
+               int i;
+
+               for (i = 0; i < MAX_NETWORK_ADDR_LEN; i++)
+                       x ^= networkAddr[i];
+
+               return x & (NAT25_HASH_SIZE - 1);
+       }
+}
+
+static inline void __network_hash_link(struct adapter *priv,
+                               struct nat25_network_db_entry *ent, int hash)
+{
+       /*  Caller must _enter_critical_bh already! */
+       ent->next_hash = priv->nethash[hash];
+       if (ent->next_hash != NULL)
+               ent->next_hash->pprev_hash = &ent->next_hash;
+       priv->nethash[hash] = ent;
+       ent->pprev_hash = &priv->nethash[hash];
+}
+
+static inline void __network_hash_unlink(struct nat25_network_db_entry *ent)
+{
+       /*  Caller must _enter_critical_bh already! */
+       *(ent->pprev_hash) = ent->next_hash;
+       if (ent->next_hash != NULL)
+               ent->next_hash->pprev_hash = ent->pprev_hash;
+       ent->next_hash = NULL;
+       ent->pprev_hash = NULL;
+}
+
+static int __nat25_db_network_lookup_and_replace(struct adapter *priv,
+                               struct sk_buff *skb, unsigned char *networkAddr)
+{
+       struct nat25_network_db_entry *db;
+       unsigned long 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);
+
+                               DEBUG_INFO("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+                                                       "%02x%02x%02x%02x%02x%02x\n",
+                                       db->macAddr[0],
+                                       db->macAddr[1],
+                                       db->macAddr[2],
+                                       db->macAddr[3],
+                                       db->macAddr[4],
+                                       db->macAddr[5],
+                                       db->networkAddr[0],
+                                       db->networkAddr[1],
+                                       db->networkAddr[2],
+                                       db->networkAddr[3],
+                                       db->networkAddr[4],
+                                       db->networkAddr[5],
+                                       db->networkAddr[6],
+                                       db->networkAddr[7],
+                                       db->networkAddr[8],
+                                       db->networkAddr[9],
+                                       db->networkAddr[10],
+                                       db->networkAddr[11],
+                                       db->networkAddr[12],
+                                       db->networkAddr[13],
+                                       db->networkAddr[14],
+                                       db->networkAddr[15],
+                                       db->networkAddr[16]);
+                       }
+                       _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(struct adapter *priv,
+                               unsigned char *macAddr, unsigned char *networkAddr)
+{
+       struct nat25_network_db_entry *db;
+       int hash;
+       unsigned long 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(struct adapter *priv)
+{
+}
+
+/*
+ *     NAT2.5 interface
+ */
+
+void nat25_db_cleanup(struct adapter *priv)
+{
+       int i;
+       unsigned long 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);
+                       kfree(f);
+                       f = g;
+               }
+       }
+       _exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+void nat25_db_expire(struct adapter *priv)
+{
+       int i;
+       unsigned long 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 (__nat25_has_expired(priv, f)) {
+                               if (atomic_dec_and_test(&f->use_count)) {
+                                       if (priv->scdb_entry == f) {
+                                               memset(priv->scdb_mac, 0, ETH_ALEN);
+                                               memset(priv->scdb_ip, 0, 4);
+                                               priv->scdb_entry = NULL;
+                                       }
+                                       __network_hash_unlink(f);
+                                       kfree(f);
+                               }
+                       }
+                       f = g;
+               }
+       }
+       _exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method)
+{
+       unsigned short protocol;
+       unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
+       unsigned int tmp;
+
+       if (skb == NULL)
+               return -1;
+
+       if ((method <= NAT25_MIN) || (method >= NAT25_MAX))
+               return -1;
+
+       protocol = be16_to_cpu(*((__be16 *)(skb->data + 2 * ETH_ALEN)));
+
+       /*---------------------------------------------------*/
+       /*                 Handle IP frame                   */
+       /*---------------------------------------------------*/
+       if (protocol == ETH_P_IP) {
+               struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
+
+               if (((unsigned char *)(iph) + (iph->ihl<<2)) >= (skb->data + ETH_HLEN + skb->len)) {
+                       DEBUG_WARN("NAT25: malformed IP packet !\n");
+                       return -1;
+               }
+
+               switch (method) {
+               case NAT25_CHECK:
+                       return -1;
+               case NAT25_INSERT:
+                       /* some 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;
+                       tmp = be32_to_cpu(iph->saddr);
+                       DEBUG_INFO("NAT25: Insert IP, SA =%08x, DA =%08x\n", tmp, iph->daddr);
+                       __nat25_generate_ipv4_network_addr(networkAddr, &tmp);
+                       /* record source IP address and , source mac address into db */
+                       __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+                       __nat25_db_print(priv);
+                       return 0;
+               case NAT25_LOOKUP:
+                       DEBUG_INFO("NAT25: Lookup IP, SA =%08x, DA =%08x\n", iph->saddr, iph->daddr);
+                       tmp = be32_to_cpu(iph->daddr);
+                       __nat25_generate_ipv4_network_addr(networkAddr, &tmp);
+
+                       if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) {
+                               if (*((unsigned char *)&iph->daddr + 3) == 0xff) {
+                                       /*  L2 is unicast but L3 is broadcast, make L2 bacome broadcast */
+                                       DEBUG_INFO("NAT25: Set DA as boardcast\n");
+                                       memset(skb->data, 0xff, ETH_ALEN);
+                               } else {
+                                       /*  forward unknow IP packet to upper TCP/IP */
+                                       DEBUG_INFO("NAT25: Replace DA with BR's MAC\n");
+                                       if ((*(u32 *)priv->br_mac) == 0 && (*(u16 *)(priv->br_mac+4)) == 0) {
+                                               printk("Re-init netdev_br_init() due to br_mac == 0!\n");
+                                               netdev_br_init(priv->pnetdev);
+                                       }
+                                       memcpy(skb->data, priv->br_mac, ETH_ALEN);
+                               }
+                       }
+                       return 0;
+               default:
+                       return -1;
+               }
+       } else if (protocol == ETH_P_ARP) {
+               /*---------------------------------------------------*/
+               /*                 Handle ARP frame                  */
+               /*---------------------------------------------------*/
+               struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN);
+               unsigned char *arp_ptr = (unsigned char *)(arp + 1);
+               unsigned int *sender, *target;
+
+               if (arp->ar_pro != __constant_htons(ETH_P_IP)) {
+                       DEBUG_WARN("NAT25: arp protocol unknown (%4x)!\n", be16_to_cpu(arp->ar_pro));
+                       return -1;
+               }
+
+               switch (method) {
+               case NAT25_CHECK:
+                       return 0;       /*  skb_copy for all ARP frame */
+               case NAT25_INSERT:
+                       DEBUG_INFO("NAT25: Insert ARP, MAC =%02x%02x%02x%02x%02x%02x\n", arp_ptr[0],
+                               arp_ptr[1], arp_ptr[2], arp_ptr[3], arp_ptr[4], arp_ptr[5]);
+
+                       /*  change to ARP sender mac address to wlan STA address */
+                       memcpy(arp_ptr, GET_MY_HWADDR(priv), ETH_ALEN);
+                       arp_ptr += arp->ar_hln;
+                       sender = (unsigned int *)arp_ptr;
+                       __nat25_generate_ipv4_network_addr(networkAddr, sender);
+                       __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+                       __nat25_db_print(priv);
+                       return 0;
+               case NAT25_LOOKUP:
+                       DEBUG_INFO("NAT25: Lookup ARP\n");
+
+                       arp_ptr += arp->ar_hln;
+                       sender = (unsigned int *)arp_ptr;
+                       arp_ptr += (arp->ar_hln + arp->ar_pln);
+                       target = (unsigned int *)arp_ptr;
+                       __nat25_generate_ipv4_network_addr(networkAddr, target);
+                       __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+                       /*  change to ARP target mac address to Lookup result */
+                       arp_ptr = (unsigned char *)(arp + 1);
+                       arp_ptr += (arp->ar_hln + arp->ar_pln);
+                       memcpy(arp_ptr, skb->data, ETH_ALEN);
+                       return 0;
+               default:
+                       return -1;
+               }
+       } else if ((protocol == ETH_P_IPX) ||
+                  (protocol <= ETH_FRAME_LEN)) {
+               /*---------------------------------------------------*/
+               /*         Handle IPX and Apple Talk frame           */
+               /*---------------------------------------------------*/
+               unsigned char ipx_header[2] = {0xFF, 0xFF};
+               struct ipxhdr   *ipx = NULL;
+               struct elapaarp *ea = NULL;
+               struct ddpehdr  *ddp = NULL;
+               unsigned char *framePtr = skb->data + ETH_HLEN;
+
+               if (protocol == ETH_P_IPX) {
+                       DEBUG_INFO("NAT25: Protocol = IPX (Ethernet II)\n");
+                       ipx = (struct ipxhdr *)framePtr;
+               } else if (protocol <= ETH_FRAME_LEN) {
+                       if (!memcmp(ipx_header, framePtr, 2)) {
+                               DEBUG_INFO("NAT25: Protocol = IPX (Ethernet 802.3)\n");
+                               ipx = (struct ipxhdr *)framePtr;
+                       } else {
+                               unsigned char ipx_8022_type =  0xE0;
+                               unsigned char snap_8022_type = 0xAA;
+
+                               if (*framePtr == snap_8022_type) {
+                                       unsigned char ipx_snap_id[5] = {0x0, 0x0, 0x0, 0x81, 0x37};             /*  IPX SNAP ID */
+                                       unsigned char aarp_snap_id[5] = {0x00, 0x00, 0x00, 0x80, 0xF3}; /*  Apple Talk AARP SNAP ID */
+                                       unsigned char ddp_snap_id[5] = {0x08, 0x00, 0x07, 0x80, 0x9B};  /*  Apple Talk DDP SNAP ID */
+
+                                       framePtr += 3;  /*  eliminate the 802.2 header */
+
+                                       if (!memcmp(ipx_snap_id, framePtr, 5)) {
+                                               framePtr += 5;  /*  eliminate the SNAP header */
+
+                                               DEBUG_INFO("NAT25: Protocol = IPX (Ethernet SNAP)\n");
+                                               ipx = (struct ipxhdr *)framePtr;
+                                       } else if (!memcmp(aarp_snap_id, framePtr, 5)) {
+                                               framePtr += 5;  /*  eliminate the SNAP header */
+
+                                               ea = (struct elapaarp *)framePtr;
+                                       } else if (!memcmp(ddp_snap_id, framePtr, 5)) {
+                                               framePtr += 5;  /*  eliminate the SNAP header */
+
+                                               ddp = (struct ddpehdr *)framePtr;
+                                       } else {
+                                               DEBUG_WARN("NAT25: Protocol = Ethernet SNAP %02x%02x%02x%02x%02x\n", framePtr[0],
+                                                       framePtr[1], framePtr[2], framePtr[3], framePtr[4]);
+                                               return -1;
+                                       }
+                               } else if (*framePtr == ipx_8022_type) {
+                                       framePtr += 3;  /*  eliminate the 802.2 header */
+
+                                       if (!memcmp(ipx_header, framePtr, 2)) {
+                                               DEBUG_INFO("NAT25: Protocol = IPX (Ethernet 802.2)\n");
+                                               ipx = (struct ipxhdr *)framePtr;
+                                       } else {
+                                               return -1;
+                                       }
+                               } else {
+                                       return -1;
+                               }
+                       }
+               } else {
+                       return -1;
+               }
+
+               /*   IPX   */
+               if (ipx != NULL) {
+                       switch (method) {
+                       case NAT25_CHECK:
+                               if (!memcmp(skb->data+ETH_ALEN, ipx->ipx_source.node, ETH_ALEN))
+                               DEBUG_INFO("NAT25: Check IPX skb_copy\n");
+                               return 0;
+                               return -1;
+                       case NAT25_INSERT:
+                               DEBUG_INFO("NAT25: Insert IPX, Dest =%08x,%02x%02x%02x%02x%02x%02x,%04x Source =%08x,%02x%02x%02x%02x%02x%02x,%04x\n",
+                                       ipx->ipx_dest.net,
+                                       ipx->ipx_dest.node[0],
+                                       ipx->ipx_dest.node[1],
+                                       ipx->ipx_dest.node[2],
+                                       ipx->ipx_dest.node[3],
+                                       ipx->ipx_dest.node[4],
+                                       ipx->ipx_dest.node[5],
+                                       ipx->ipx_dest.sock,
+                                       ipx->ipx_source.net,
+                                       ipx->ipx_source.node[0],
+                                       ipx->ipx_source.node[1],
+                                       ipx->ipx_source.node[2],
+                                       ipx->ipx_source.node[3],
+                                       ipx->ipx_source.node[4],
+                                       ipx->ipx_source.node[5],
+                                       ipx->ipx_source.sock);
+
+                               if (!memcmp(skb->data+ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) {
+                                       DEBUG_INFO("NAT25: Use IPX Net, and Socket as network addr\n");
+
+                                       __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_source.net, &ipx->ipx_source.sock);
+
+                                       /*  change IPX source node addr to wlan STA address */
+                                       memcpy(ipx->ipx_source.node, GET_MY_HWADDR(priv), ETH_ALEN);
+                               } else {
+                                       __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_source.net, ipx->ipx_source.node);
+                               }
+                               __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+                               __nat25_db_print(priv);
+                               return 0;
+                       case NAT25_LOOKUP:
+                               if (!memcmp(GET_MY_HWADDR(priv), ipx->ipx_dest.node, ETH_ALEN)) {
+                                       DEBUG_INFO("NAT25: Lookup IPX, Modify Destination IPX Node addr\n");
+
+                                       __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_dest.net, &ipx->ipx_dest.sock);
+
+                                       __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+
+                                       /*  replace IPX destination node addr with Lookup destination MAC addr */
+                                       memcpy(ipx->ipx_dest.node, skb->data, ETH_ALEN);
+                               } else {
+                                       __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_dest.net, ipx->ipx_dest.node);
+
+                                       __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+                               }
+                               return 0;
+                       default:
+                               return -1;
+                       }
+               } else if (ea != NULL) {
+                       /* Sanity check fields. */
+                       if (ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN) {
+                               DEBUG_WARN("NAT25: Appletalk AARP Sanity check fail!\n");
+                               return -1;
+                       }
+
+                       switch (method) {
+                       case NAT25_CHECK:
+                               return 0;
+                       case NAT25_INSERT:
+                               /*  change to AARP source mac address to wlan STA address */
+                               memcpy(ea->hw_src, GET_MY_HWADDR(priv), ETH_ALEN);
+
+                               DEBUG_INFO("NAT25: Insert AARP, Source =%d,%d Destination =%d,%d\n",
+                                       ea->pa_src_net,
+                                       ea->pa_src_node,
+                                       ea->pa_dst_net,
+                                       ea->pa_dst_node);
+
+                               __nat25_generate_apple_network_addr(networkAddr, &ea->pa_src_net, &ea->pa_src_node);
+
+                               __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+                               __nat25_db_print(priv);
+                               return 0;
+                       case NAT25_LOOKUP:
+                               DEBUG_INFO("NAT25: Lookup AARP, Source =%d,%d Destination =%d,%d\n",
+                                       ea->pa_src_net,
+                                       ea->pa_src_node,
+                                       ea->pa_dst_net,
+                                       ea->pa_dst_node);
+
+                               __nat25_generate_apple_network_addr(networkAddr, &ea->pa_dst_net, &ea->pa_dst_node);
+
+                               __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+
+                               /*  change to AARP destination mac address to Lookup result */
+                               memcpy(ea->hw_dst, skb->data, ETH_ALEN);
+                               return 0;
+                       default:
+                               return -1;
+                       }
+               } else if (ddp != NULL) {
+                       switch (method) {
+                       case NAT25_CHECK:
+                               return -1;
+                       case NAT25_INSERT:
+                               DEBUG_INFO("NAT25: Insert DDP, Source =%d,%d Destination =%d,%d\n",
+                                       ddp->deh_snet,
+                                       ddp->deh_snode,
+                                       ddp->deh_dnet,
+                                       ddp->deh_dnode);
+
+                               __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_snet, &ddp->deh_snode);
+
+                               __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+                               __nat25_db_print(priv);
+                               return 0;
+                       case NAT25_LOOKUP:
+                               DEBUG_INFO("NAT25: Lookup DDP, Source =%d,%d Destination =%d,%d\n",
+                                       ddp->deh_snet,
+                                       ddp->deh_snode,
+                                       ddp->deh_dnet,
+                                       ddp->deh_dnode);
+                               __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_dnet, &ddp->deh_dnode);
+                               __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+                               return 0;
+                       default:
+                               return -1;
+                       }
+               }
+
+               return -1;
+       } else if ((protocol == ETH_P_PPP_DISC) ||
+                  (protocol == ETH_P_PPP_SES)) {
+               /*---------------------------------------------------*/
+               /*                Handle PPPoE frame                 */
+               /*---------------------------------------------------*/
+               struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
+               unsigned short *pMagic;
+
+               switch (method) {
+               case NAT25_CHECK:
+                       if (ph->sid == 0)
+                               return 0;
+                       return 1;
+               case NAT25_INSERT:
+                       if (ph->sid == 0) {     /*  Discovery phase according to tag */
+                               if (ph->code == PADI_CODE || ph->code == PADR_CODE) {
+                                       if (priv->ethBrExtInfo.addPPPoETag) {
+                                               struct pppoe_tag *tag, *pOldTag;
+                                               unsigned char tag_buf[40];
+                                               int old_tag_len = 0;
+
+                                               tag = (struct pppoe_tag *)tag_buf;
+                                               pOldTag = (struct pppoe_tag *)__nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID));
+                                               if (pOldTag) { /*  if SID existed, copy old value and delete it */
+                                                       old_tag_len = ntohs(pOldTag->tag_len);
+                                                       if (old_tag_len+TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN > sizeof(tag_buf)) {
+                                                               DEBUG_ERR("SID tag length too long!\n");
+                                                               return -1;
+                                                       }
+
+                                                       memcpy(tag->tag_data+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN,
+                                                               pOldTag->tag_data, old_tag_len);
+
+                                                       if (skb_pull_and_merge(skb, (unsigned char *)pOldTag, TAG_HDR_LEN+old_tag_len) < 0) {
+                                                               DEBUG_ERR("call skb_pull_and_merge() failed in PADI/R packet!\n");
+                                                               return -1;
+                                                       }
+                                                       ph->length = htons(ntohs(ph->length)-TAG_HDR_LEN-old_tag_len);
+                                               }
+
+                                               tag->tag_type = PTT_RELAY_SID;
+                                               tag->tag_len = htons(MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN+old_tag_len);
+
+                                               /*  insert the magic_code+client mac in relay tag */
+                                               pMagic = (unsigned short *)tag->tag_data;
+                                               *pMagic = htons(MAGIC_CODE);
+                                               memcpy(tag->tag_data+MAGIC_CODE_LEN, skb->data+ETH_ALEN, ETH_ALEN);
+
+                                               /* Add relay tag */
+                                               if (__nat25_add_pppoe_tag(skb, tag) < 0)
+                                                       return -1;
+
+                                               DEBUG_INFO("NAT25: Insert PPPoE, forward %s packet\n",
+                                                                               (ph->code == PADI_CODE ? "PADI" : "PADR"));
+                                       } else { /*  not add relay tag */
+                                               if (priv->pppoe_connection_in_progress &&
+                                                               memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN))  {
+                                                       DEBUG_ERR("Discard PPPoE packet due to another PPPoE connection is in progress!\n");
+                                                       return -2;
+                                               }
+
+                                               if (priv->pppoe_connection_in_progress == 0)
+                                                       memcpy(priv->pppoe_addr, skb->data+ETH_ALEN, ETH_ALEN);
+
+                                               priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE;
+                                       }
+                               } else {
+                                       return -1;
+                               }
+                       } else {        /*  session phase */
+                               DEBUG_INFO("NAT25: Insert PPPoE, insert session packet to %s\n", skb->dev->name);
+
+                               __nat25_generate_pppoe_network_addr(networkAddr, skb->data, &(ph->sid));
+
+                               __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+                               __nat25_db_print(priv);
+
+                               if (!priv->ethBrExtInfo.addPPPoETag &&
+                                   priv->pppoe_connection_in_progress &&
+                                   !memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN))
+                                       priv->pppoe_connection_in_progress = 0;
+                       }
+                       return 0;
+               case NAT25_LOOKUP:
+                       if (ph->code == PADO_CODE || ph->code == PADS_CODE) {
+                               if (priv->ethBrExtInfo.addPPPoETag) {
+                                       struct pppoe_tag *tag;
+                                       unsigned char *ptr;
+                                       unsigned short tagType, tagLen;
+                                       int offset = 0;
+
+                                       ptr = __nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID));
+                                       if (ptr == NULL) {
+                                               DEBUG_ERR("Fail to find PTT_RELAY_SID in FADO!\n");
+                                               return -1;
+                                       }
+
+                                       tag = (struct pppoe_tag *)ptr;
+                                       tagType = (unsigned short)((ptr[0] << 8) + ptr[1]);
+                                       tagLen = (unsigned short)((ptr[2] << 8) + ptr[3]);
+
+                                       if ((tagType != ntohs(PTT_RELAY_SID)) || (tagLen < (MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN))) {
+                                               DEBUG_ERR("Invalid PTT_RELAY_SID tag length [%d]!\n", tagLen);
+                                               return -1;
+                                       }
+
+                                       pMagic = (unsigned short *)tag->tag_data;
+                                       if (ntohs(*pMagic) != MAGIC_CODE) {
+                                               DEBUG_ERR("Can't find MAGIC_CODE in %s packet!\n",
+                                                       (ph->code == PADO_CODE ? "PADO" : "PADS"));
+                                               return -1;
+                                       }
+
+                                       memcpy(skb->data, tag->tag_data+MAGIC_CODE_LEN, ETH_ALEN);
+
+                                       if (tagLen > MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN)
+                                               offset = TAG_HDR_LEN;
+
+                                       if (skb_pull_and_merge(skb, ptr+offset, TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN-offset) < 0) {
+                                               DEBUG_ERR("call skb_pull_and_merge() failed in PADO packet!\n");
+                                               return -1;
+                                       }
+                                       ph->length = htons(ntohs(ph->length)-(TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN-offset));
+                                       if (offset > 0)
+                                               tag->tag_len = htons(tagLen-MAGIC_CODE_LEN-RTL_RELAY_TAG_LEN);
+
+                                       DEBUG_INFO("NAT25: Lookup PPPoE, forward %s Packet from %s\n",
+                                               (ph->code == PADO_CODE ? "PADO" : "PADS"),      skb->dev->name);
+                               } else { /*  not add relay tag */
+                                       if (!priv->pppoe_connection_in_progress) {
+                                               DEBUG_ERR("Discard PPPoE packet due to no connection in progresss!\n");
+                                               return -1;
+                                       }
+                                       memcpy(skb->data, priv->pppoe_addr, ETH_ALEN);
+                                       priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE;
+                               }
+                       } else {
+                               if (ph->sid != 0) {
+                                       DEBUG_INFO("NAT25: Lookup PPPoE, lookup session packet from %s\n", skb->dev->name);
+                                       __nat25_generate_pppoe_network_addr(networkAddr, skb->data+ETH_ALEN, &(ph->sid));
+                                       __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+                                       __nat25_db_print(priv);
+                               } else {
+                                       return -1;
+                               }
+                       }
+                       return 0;
+               default:
+                       return -1;
+               }
+       } else if (protocol == 0x888e) {
+               /*---------------------------------------------------*/
+               /*                 Handle EAP frame                  */
+               /*---------------------------------------------------*/
+               switch (method) {
+               case NAT25_CHECK:
+                       return -1;
+               case NAT25_INSERT:
+                       return 0;
+               case NAT25_LOOKUP:
+                       return 0;
+               default:
+                       return -1;
+               }
+       } else if ((protocol == 0xe2ae) || (protocol == 0xe2af)) {
+               /*---------------------------------------------------*/
+               /*         Handle C-Media proprietary frame          */
+               /*---------------------------------------------------*/
+               switch (method) {
+               case NAT25_CHECK:
+                       return -1;
+               case NAT25_INSERT:
+                       return 0;
+               case NAT25_LOOKUP:
+                       return 0;
+               default:
+                       return -1;
+               }
+       } else if (protocol == ETH_P_IPV6) {
+               /*------------------------------------------------*/
+               /*         Handle IPV6 frame                      */
+               /*------------------------------------------------*/
+               struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN);
+
+               if (sizeof(*iph) >= (skb->len - ETH_HLEN)) {
+                       DEBUG_WARN("NAT25: malformed IPv6 packet !\n");
+                       return -1;
+               }
+
+               switch (method) {
+               case NAT25_CHECK:
+                       if (skb->data[0] & 1)
+                               return 0;
+                       return -1;
+               case NAT25_INSERT:
+                       DEBUG_INFO("NAT25: Insert IP, SA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x,"
+                                                       " DA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n",
+                               iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3],
+                               iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7],
+                               iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3],
+                               iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]);
+
+                       if (memcmp(&iph->saddr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16)) {
+                               __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->saddr);
+                               __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+                               __nat25_db_print(priv);
+
+                               if (iph->nexthdr == IPPROTO_ICMPV6 &&
+                                               skb->len > (ETH_HLEN +  sizeof(*iph) + 4)) {
+                                       if (update_nd_link_layer_addr(skb->data + ETH_HLEN + sizeof(*iph),
+                                                                     skb->len - ETH_HLEN - sizeof(*iph), GET_MY_HWADDR(priv))) {
+                                               struct icmp6hdr  *hdr = (struct icmp6hdr *)(skb->data + ETH_HLEN + sizeof(*iph));
+                                               hdr->icmp6_cksum = 0;
+                                               hdr->icmp6_cksum = csum_ipv6_magic(&iph->saddr, &iph->daddr,
+                                                                               iph->payload_len,
+                                                                               IPPROTO_ICMPV6,
+                                                                               csum_partial((__u8 *)hdr, iph->payload_len, 0));
+                                       }
+                               }
+                       }
+                       return 0;
+               case NAT25_LOOKUP:
+                       DEBUG_INFO("NAT25: Lookup IP, SA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x, DA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n",
+                                  iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3],
+                                  iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7],
+                                  iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3],
+                                  iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]);
+                       __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->daddr);
+                       __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+                       return 0;
+               default:
+                       return -1;
+               }
+       }
+       return -1;
+}
+
+int nat25_handle_frame(struct adapter *priv, struct sk_buff *skb)
+{
+       if (!(skb->data[0] & 1)) {
+               int is_vlan_tag = 0, i, retval = 0;
+               unsigned short vlan_hdr = 0;
+               unsigned short protocol;
+
+               protocol = be16_to_cpu(*((__be16 *)(skb->data + 2 * ETH_ALEN)));
+               if (protocol == ETH_P_8021Q) {
+                       is_vlan_tag = 1;
+                       vlan_hdr = *((unsigned short *)(skb->data+ETH_ALEN*2+2));
+                       for (i = 0; i < 6; i++)
+                               *((unsigned short *)(skb->data+ETH_ALEN*2+2-i*2)) = *((unsigned short *)(skb->data+ETH_ALEN*2-2-i*2));
+                       skb_pull(skb, 4);
+               }
+
+               if (!priv->ethBrExtInfo.nat25_disable) {
+                       unsigned long 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 &&
+                           (be16_to_cpu(*((__be16 *)(skb->data+ETH_ALEN*2))) == ETH_P_IP) &&
+                           !memcmp(priv->scdb_ip, skb->data+ETH_HLEN+16, 4)) {
+                               memcpy(skb->data, priv->scdb_mac, ETH_ALEN);
+
+                               _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 (((be16_to_cpu(*((__be16 *)(skb->data+ETH_ALEN*2))) == ETH_P_IP) &&
+                           !memcmp(priv->br_ip, skb->data+ETH_HLEN+16, 4)) ||
+                           ((be16_to_cpu(*((__be16 *)(skb->data+ETH_ALEN*2))) == ETH_P_ARP) &&
+                           !memcmp(priv->br_ip, skb->data+ETH_HLEN+24, 4))) {
+                               /*  for traffic to upper TCP/IP */
+                               retval = nat25_db_handle(priv, skb, NAT25_LOOKUP);
+                       }
+               }
+
+               if (is_vlan_tag) {
+                       skb_push(skb, 4);
+                       for (i = 0; i < 6; i++)
+                               *((unsigned short *)(skb->data+i*2)) = *((unsigned short *)(skb->data+4+i*2));
+                       *((__be16 *)(skb->data+ETH_ALEN*2)) = __constant_htons(ETH_P_8021Q);
+                       *((unsigned short *)(skb->data+ETH_ALEN*2+2)) = vlan_hdr;
+               }
+
+               if (retval == -1) {
+                       /* DEBUG_ERR("NAT25: Lookup fail!\n"); */
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+#define SERVER_PORT                    67
+#define CLIENT_PORT                    68
+#define DHCP_MAGIC                     0x63825363
+#define BROADCAST_FLAG         0x8000
+
+struct dhcpMessage {
+       u_int8_t op;
+       u_int8_t htype;
+       u_int8_t hlen;
+       u_int8_t hops;
+       u_int32_t xid;
+       u_int16_t secs;
+       u_int16_t flags;
+       u_int32_t ciaddr;
+       u_int32_t yiaddr;
+       u_int32_t siaddr;
+       u_int32_t giaddr;
+       u_int8_t chaddr[16];
+       u_int8_t sname[64];
+       u_int8_t file[128];
+       u_int32_t cookie;
+       u_int8_t options[308]; /* 312 - cookie */
+};
+
+void dhcp_flag_bcast(struct adapter *priv, struct sk_buff *skb)
+{
+       if (skb == NULL)
+               return;
+
+       if (!priv->ethBrExtInfo.dhcp_bcst_disable) {
+               __be16 protocol = *((__be16 *)(skb->data + 2 * ETH_ALEN));
+
+               if (protocol == __constant_htons(ETH_P_IP)) { /*  IP */
+                       struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
+
+                       if (iph->protocol == IPPROTO_UDP) { /*  UDP */
+                               struct udphdr *udph = (struct udphdr *)((size_t)iph + (iph->ihl << 2));
+
+                               if ((udph->source == __constant_htons(CLIENT_PORT)) &&
+                                   (udph->dest == __constant_htons(SERVER_PORT))) { /*  DHCP request */
+                                       struct dhcpMessage *dhcph =
+                                               (struct dhcpMessage *)((size_t)udph + sizeof(struct udphdr));
+                                       u32 cookie = be32_to_cpu((__be32)dhcph->cookie);
+
+                                       if (cookie == DHCP_MAGIC) { /*  match magic word */
+                                               if (!(dhcph->flags & htons(BROADCAST_FLAG))) {
+                                                       /*  if not broadcast */
+                                                       register int sum = 0;
+
+                                                       DEBUG_INFO("DHCP: change flag of DHCP request to broadcast.\n");
+                                                       /*  or BROADCAST flag */
+                                                       dhcph->flags |= htons(BROADCAST_FLAG);
+                                                       /*  recalculate checksum */
+                                                       sum = ~(udph->check) & 0xffff;
+                                                       sum += be16_to_cpu(dhcph->flags);
+                                                       while (sum >> 16)
+                                                               sum = (sum & 0xffff) + (sum >> 16);
+                                                       udph->check = ~sum;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+
+void *scdb_findEntry(struct adapter *priv, unsigned char *macAddr,
+                               unsigned char *ipAddr)
+{
+       unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
+       struct nat25_network_db_entry *db;
+       int hash;
+       /* unsigned long 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/rtl8188eu/core/rtw_cmd.c b/drivers/staging/rtl8188eu/core/rtw_cmd.c
new file mode 100644 (file)
index 0000000..859fc19
--- /dev/null
@@ -0,0 +1,2364 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_CMD_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <cmd_osdep.h>
+#include <mlme_osdep.h>
+#include <rtw_br_ext.h>
+#include <rtw_mlme_ext.h>
+
+/*
+Caller and the rtw_cmd_thread can protect cmd_q by spin_lock.
+No irqsave is necessary.
+*/
+
+int    _rtw_init_cmd_priv (struct      cmd_priv *pcmdpriv)
+{
+       int res = _SUCCESS;
+
+_func_enter_;
+
+       _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_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_t)(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_t)(pcmdpriv->rsp_allocated_buf) & 3);
+
+       pcmdpriv->cmd_issued_cnt = 0;
+       pcmdpriv->cmd_done_cnt = 0;
+       pcmdpriv->rsp_cnt = 0;
+exit:
+_func_exit_;
+       return res;
+}
+
+static void c2h_wk_callback(struct work_struct *work);
+
+int _rtw_init_evt_priv(struct evt_priv *pevtpriv)
+{
+       int res = _SUCCESS;
+
+_func_enter_;
+
+       /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
+       ATOMIC_SET(&pevtpriv->event_seq, 0);
+       pevtpriv->evt_done_cnt = 0;
+
+       _init_workitem(&pevtpriv->c2h_wk, c2h_wk_callback, NULL);
+       pevtpriv->c2h_wk_alive = false;
+       pevtpriv->c2h_queue = rtw_cbuf_alloc(C2H_QUEUE_MAX_LEN+1);
+
+_func_exit_;
+
+       return res;
+}
+
+void rtw_free_evt_priv(struct  evt_priv *pevtpriv)
+{
+_func_enter_;
+
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+rtw_free_evt_priv\n"));
+
+       _cancel_workitem_sync(&pevtpriv->c2h_wk);
+       while (pevtpriv->c2h_wk_alive)
+               rtw_msleep_os(10);
+
+       while (!rtw_cbuf_empty(pevtpriv->c2h_queue)) {
+               void *c2h = rtw_cbuf_pop(pevtpriv->c2h_queue);
+               if (c2h != NULL && c2h != (void *)pevtpriv)
+                       kfree(c2h);
+       }
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("-rtw_free_evt_priv\n"));
+
+_func_exit_;
+}
+
+void _rtw_free_cmd_priv (struct        cmd_priv *pcmdpriv)
+{
+_func_enter_;
+
+       if (pcmdpriv) {
+               _rtw_spinlock_free(&(pcmdpriv->cmd_queue.lock));
+               _rtw_free_sema(&(pcmdpriv->cmd_queue_sema));
+               _rtw_free_sema(&(pcmdpriv->terminate_cmdthread_sema));
+
+               if (pcmdpriv->cmd_allocated_buf)
+                       kfree(pcmdpriv->cmd_allocated_buf);
+
+               if (pcmdpriv->rsp_allocated_buf)
+                       kfree(pcmdpriv->rsp_allocated_buf);
+       }
+_func_exit_;
+}
+
+/*
+Calling Context:
+
+rtw_enqueue_cmd can only be called between kernel thread,
+since only spin_lock is used.
+
+ISR/Call-Back functions can't call this sub-function.
+
+*/
+
+int    _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj)
+{
+       unsigned long irqL;
+
+_func_enter_;
+
+       if (obj == NULL)
+               goto exit;
+
+       /* _enter_critical_bh(&queue->lock, &irqL); */
+       _enter_critical(&queue->lock, &irqL);
+
+       rtw_list_insert_tail(&obj->list, &queue->queue);
+
+       /* _exit_critical_bh(&queue->lock, &irqL); */
+       _exit_critical(&queue->lock, &irqL);
+
+exit:
+
+_func_exit_;
+
+       return _SUCCESS;
+}
+
+struct cmd_obj *_rtw_dequeue_cmd(struct __queue *queue)
+{
+       unsigned long irqL;
+       struct cmd_obj *obj;
+
+_func_enter_;
+
+       /* _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);
+
+_func_exit_;
+
+       return obj;
+}
+
+u32    rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
+{
+       u32     res;
+_func_enter_;
+       res = _rtw_init_cmd_priv (pcmdpriv);
+_func_exit_;
+       return res;
+}
+
+u32    rtw_init_evt_priv (struct       evt_priv *pevtpriv)
+{
+       int     res;
+_func_enter_;
+       res = _rtw_init_evt_priv(pevtpriv);
+_func_exit_;
+       return res;
+}
+
+void rtw_free_cmd_priv(struct  cmd_priv *pcmdpriv)
+{
+_func_enter_;
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("rtw_free_cmd_priv\n"));
+       _rtw_free_cmd_priv(pcmdpriv);
+_func_exit_;
+}
+
+int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
+{
+       u8 bAllow = false; /* set to true to allow enqueuing cmd when hw_init_completed is false */
+
+       /* To decide allow or not */
+       if ((pcmdpriv->padapter->pwrctrlpriv.bHWPwrPindetect) &&
+           (!pcmdpriv->padapter->registrypriv.usbss_enable)) {
+               if (cmd_obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) {
+                       struct drvextra_cmd_parm        *pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)cmd_obj->parmbuf;
+                       if (pdrvextra_cmd_parm->ec_id == POWER_SAVING_CTRL_WK_CID)
+                               bAllow = true;
+               }
+       }
+
+       if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan))
+               bAllow = true;
+
+       if ((!pcmdpriv->padapter->hw_init_completed && !bAllow) ||
+           !pcmdpriv->cmdthd_running)  /* com_thread not running */
+               return _FAIL;
+       return _SUCCESS;
+}
+
+u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
+{
+       int res = _FAIL;
+       struct adapter *padapter = pcmdpriv->padapter;
+
+_func_enter_;
+
+       if (cmd_obj == NULL)
+               goto exit;
+
+       cmd_obj->padapter = padapter;
+
+       res = rtw_cmd_filter(pcmdpriv, cmd_obj);
+       if (_FAIL == res) {
+               rtw_free_cmd_obj(cmd_obj);
+               goto exit;
+       }
+
+       res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj);
+
+       if (res == _SUCCESS)
+               _rtw_up_sema(&pcmdpriv->cmd_queue_sema);
+
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv)
+{
+       struct cmd_obj *cmd_obj;
+
+_func_enter_;
+
+       cmd_obj = _rtw_dequeue_cmd(&pcmdpriv->cmd_queue);
+
+_func_exit_;
+       return cmd_obj;
+}
+
+void rtw_cmd_clr_isr(struct    cmd_priv *pcmdpriv)
+{
+_func_enter_;
+       pcmdpriv->cmd_done_cnt++;
+       /* _rtw_up_sema(&(pcmdpriv->cmd_done_sema)); */
+_func_exit_;
+}
+
+void rtw_free_cmd_obj(struct cmd_obj *pcmd)
+{
+_func_enter_;
+
+       if ((pcmd->cmdcode != _JoinBss_CMD_) && (pcmd->cmdcode != _CreateBss_CMD_)) {
+               /* free parmbuf in cmd_obj */
+               kfree(pcmd->parmbuf);
+       }
+
+       if (pcmd->rsp != NULL) {
+               if (pcmd->rspsz != 0) {
+                       /* free rsp in cmd_obj */
+                       kfree(pcmd->rsp);
+               }
+       }
+
+       /* free cmd_obj */
+       kfree(pcmd);
+
+_func_exit_;
+}
+
+int rtw_cmd_thread(void *context)
+{
+       u8 ret;
+       struct cmd_obj *pcmd;
+       u8 *pcmdbuf;
+       u8 (*cmd_hdl)(struct adapter *padapter, u8 *pbuf);
+       void (*pcmd_callback)(struct adapter *dev, struct cmd_obj *pcmd);
+       struct adapter *padapter = (struct adapter *)context;
+       struct cmd_priv *pcmdpriv = &(padapter->cmdpriv);
+
+_func_enter_;
+
+       thread_enter("RTW_CMD_THREAD");
+
+       pcmdbuf = pcmdpriv->cmd_buf;
+
+       pcmdpriv->cmdthd_running = true;
+       _rtw_up_sema(&pcmdpriv->terminate_cmdthread_sema);
+
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("start r871x rtw_cmd_thread !!!!\n"));
+
+       while (1) {
+               if (_rtw_down_sema(&pcmdpriv->cmd_queue_sema) == _FAIL)
+                       break;
+
+               if (padapter->bDriverStopped ||
+                   padapter->bSurpriseRemoved) {
+                       DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n",
+                               __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__);
+                       break;
+               }
+_next:
+               if (padapter->bDriverStopped ||
+                   padapter->bSurpriseRemoved) {
+                       DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n",
+                               __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__);
+                       break;
+               }
+
+               pcmd = rtw_dequeue_cmd(pcmdpriv);
+               if (!pcmd)
+                       continue;
+
+               if (_FAIL == rtw_cmd_filter(pcmdpriv, pcmd)) {
+                       pcmd->res = H2C_DROPPED;
+                       goto post_process;
+               }
+
+               pcmdpriv->cmd_issued_cnt++;
+
+               pcmd->cmdsz = _RND4((pcmd->cmdsz));/* _RND4 */
+
+               memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz);
+
+               if (pcmd->cmdcode <= (sizeof(wlancmds) / sizeof(struct cmd_hdl))) {
+                       cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns;
+
+                       if (cmd_hdl) {
+                               ret = cmd_hdl(pcmd->padapter, pcmdbuf);
+                               pcmd->res = ret;
+                       }
+
+                       pcmdpriv->cmd_seq++;
+               } else {
+                       pcmd->res = H2C_PARAMETERS_ERROR;
+               }
+
+               cmd_hdl = NULL;
+
+post_process:
+
+               /* call callback function for post-processed */
+               if (pcmd->cmdcode <= (sizeof(rtw_cmd_callback) / sizeof(struct _cmd_callback))) {
+                       pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback;
+                       if (pcmd_callback == NULL) {
+                               RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("mlme_cmd_hdl(): pcmd_callback = 0x%p, cmdcode = 0x%x\n", pcmd_callback, pcmd->cmdcode));
+                               rtw_free_cmd_obj(pcmd);
+                       } else {
+                               /* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */
+                               pcmd_callback(pcmd->padapter, pcmd);/* need conider that free cmd_obj in rtw_cmd_callback */
+                       }
+               } else {
+                       RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("%s: cmdcode = 0x%x callback not defined!\n", __func__, pcmd->cmdcode));
+                       rtw_free_cmd_obj(pcmd);
+               }
+
+               flush_signals_thread();
+
+               goto _next;
+       }
+       pcmdpriv->cmdthd_running = false;
+
+       /*  free all cmd_obj resources */
+       do {
+               pcmd = rtw_dequeue_cmd(pcmdpriv);
+               if (pcmd == NULL)
+                       break;
+
+               /* DBG_88E("%s: leaving... drop cmdcode:%u\n", __func__, pcmd->cmdcode); */
+
+               rtw_free_cmd_obj(pcmd);
+       } while (1);
+
+       _rtw_up_sema(&pcmdpriv->terminate_cmdthread_sema);
+
+_func_exit_;
+
+       thread_exit();
+}
+
+u8 rtw_setstandby_cmd(struct adapter *padapter, uint action)
+{
+       struct cmd_obj *ph2c;
+       struct usb_suspend_parm *psetusbsuspend;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+       u8 ret = _SUCCESS;
+
+_func_enter_;
+
+       ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (ph2c == NULL) {
+               ret = _FAIL;
+               goto exit;
+       }
+
+       psetusbsuspend = (struct usb_suspend_parm *)rtw_zmalloc(sizeof(struct usb_suspend_parm));
+       if (psetusbsuspend == NULL) {
+               kfree(ph2c);
+               ret = _FAIL;
+               goto exit;
+       }
+
+       psetusbsuspend->action = action;
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, psetusbsuspend, GEN_CMD_CODE(_SetUsbSuspend));
+
+       ret = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+       return ret;
+}
+
+/*
+rtw_sitesurvey_cmd(~)
+       ### NOTE:#### (!!!!)
+       MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock
+*/
+u8 rtw_sitesurvey_cmd(struct adapter  *padapter, struct ndis_802_11_ssid *ssid, int ssid_num,
+       struct rtw_ieee80211_channel *ch, int ch_num)
+{
+       u8 res = _FAIL;
+       struct cmd_obj          *ph2c;
+       struct sitesurvey_parm  *psurveyPara;
+       struct cmd_priv         *pcmdpriv = &padapter->cmdpriv;
+       struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+       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) {
+               kfree(ph2c);
+               return _FAIL;
+       }
+
+       rtw_free_network_queue(padapter, false);
+
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("%s: flush network queue\n", __func__));
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey));
+
+       /* psurveyPara->bsslimit = 48; */
+       psurveyPara->scan_mode = pmlmepriv->scan_mode;
+
+       /* prepare ssid list */
+       if (ssid) {
+               int i;
+               for (i = 0; i < ssid_num && i < RTW_SSID_SCAN_AMOUNT; i++) {
+                       if (ssid[i].SsidLength) {
+                               memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(struct ndis_802_11_ssid));
+                               psurveyPara->ssid_num++;
+                               if (0)
+                               DBG_88E(FUNC_ADPT_FMT" ssid:(%s, %d)\n", FUNC_ADPT_ARG(padapter),
+                                       psurveyPara->ssid[i].Ssid, psurveyPara->ssid[i].SsidLength);
+                       }
+               }
+       }
+
+       /* prepare channel list */
+       if (ch) {
+               int i;
+               for (i = 0; i < ch_num && i < RTW_CHANNEL_SCAN_AMOUNT; i++) {
+                       if (ch[i].hw_value && !(ch[i].flags & RTW_IEEE80211_CHAN_DISABLED)) {
+                               memcpy(&psurveyPara->ch[i], &ch[i], sizeof(struct rtw_ieee80211_channel));
+                               psurveyPara->ch_num++;
+                               if (0)
+                               DBG_88E(FUNC_ADPT_FMT" ch:%u\n", FUNC_ADPT_ARG(padapter),
+                                       psurveyPara->ch[i].hw_value);
+                       }
+               }
+       }
+
+       set_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
+
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+       if (res == _SUCCESS) {
+               pmlmepriv->scan_start_time = rtw_get_current_time();
+
+               _set_timer(&pmlmepriv->scan_to_timer, SCANNING_TIMEOUT);
+
+               rtw_led_control(padapter, LED_CTL_SITE_SURVEY);
+
+               pmlmepriv->scan_interval = SCAN_INTERVAL;/*  30*2 sec = 60sec */
+       } else {
+               _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+       }
+
+_func_exit_;
+
+       return res;
+}
+
+u8 rtw_setdatarate_cmd(struct adapter *padapter, u8 *rateset)
+{
+       struct cmd_obj *ph2c;
+       struct setdatarate_parm *pbsetdataratepara;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       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) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara, GEN_CMD_CODE(_SetDataRate));
+       pbsetdataratepara->mac_id = 5;
+       memcpy(pbsetdataratepara->datarates, rateset, NumRates);
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+u8 rtw_setbasicrate_cmd(struct adapter *padapter, u8 *rateset)
+{
+       struct cmd_obj *ph2c;
+       struct setbasicrate_parm *pssetbasicratepara;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (ph2c == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+       pssetbasicratepara = (struct setbasicrate_parm *)rtw_zmalloc(sizeof(struct setbasicrate_parm));
+
+       if (pssetbasicratepara == NULL) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, pssetbasicratepara, _SetBasicRate_CMD_);
+
+       memcpy(pssetbasicratepara->basicrates, rateset, NumRates);
+
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+
+/*
+unsigned char rtw_setphy_cmd(unsigned char  *adapter)
+
+1.  be called only after rtw_update_registrypriv_dev_network(~) or mp testing program
+2.  for AdHoc/Ap mode or mp mode?
+
+*/
+u8 rtw_setphy_cmd(struct adapter *padapter, u8 modem, u8 ch)
+{
+       struct cmd_obj *ph2c;
+       struct setphy_parm *psetphypara;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (ph2c == NULL) {
+               res = _FAIL;
+               goto exit;
+               }
+       psetphypara = (struct setphy_parm *)rtw_zmalloc(sizeof(struct setphy_parm));
+
+       if (psetphypara == NULL) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, psetphypara, _SetPhy_CMD_);
+
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("CH =%d, modem =%d", ch, modem));
+
+       psetphypara->modem = modem;
+       psetphypara->rfchannel = ch;
+
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+       return res;
+}
+
+u8 rtw_setbbreg_cmd(struct adapter *padapter, u8 offset, u8 val)
+{
+       struct cmd_obj *ph2c;
+       struct writeBB_parm *pwritebbparm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8      res = _SUCCESS;
+
+_func_enter_;
+       ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (ph2c == NULL) {
+               res = _FAIL;
+               goto exit;
+               }
+       pwritebbparm = (struct writeBB_parm *)rtw_zmalloc(sizeof(struct writeBB_parm));
+
+       if (pwritebbparm == NULL) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, pwritebbparm, GEN_CMD_CODE(_SetBBReg));
+
+       pwritebbparm->offset = offset;
+       pwritebbparm->value = val;
+
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+       return res;
+}
+
+u8 rtw_getbbreg_cmd(struct adapter  *padapter, u8 offset, u8 *pval)
+{
+       struct cmd_obj *ph2c;
+       struct readBB_parm *prdbbparm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8      res = _SUCCESS;
+
+_func_enter_;
+       ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (ph2c == NULL) {
+               res = _FAIL;
+               goto exit;
+               }
+       prdbbparm = (struct readBB_parm *)rtw_zmalloc(sizeof(struct readBB_parm));
+
+       if (prdbbparm == NULL) {
+               kfree(ph2c);
+               return _FAIL;
+       }
+
+       _rtw_init_listhead(&ph2c->list);
+       ph2c->cmdcode = GEN_CMD_CODE(_GetBBReg);
+       ph2c->parmbuf = (unsigned char *)prdbbparm;
+       ph2c->cmdsz =  sizeof(struct readBB_parm);
+       ph2c->rsp = pval;
+       ph2c->rspsz = sizeof(struct readBB_rsp);
+
+       prdbbparm->offset = offset;
+
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+       return res;
+}
+
+u8 rtw_setrfreg_cmd(struct adapter  *padapter, u8 offset, u32 val)
+{
+       struct cmd_obj *ph2c;
+       struct writeRF_parm *pwriterfparm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8      res = _SUCCESS;
+_func_enter_;
+       ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (ph2c == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+       pwriterfparm = (struct writeRF_parm *)rtw_zmalloc(sizeof(struct writeRF_parm));
+
+       if (pwriterfparm == NULL) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg));
+
+       pwriterfparm->offset = offset;
+       pwriterfparm->value = val;
+
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+       return res;
+}
+
+u8 rtw_getrfreg_cmd(struct adapter  *padapter, u8 offset, u8 *pval)
+{
+       struct cmd_obj *ph2c;
+       struct readRF_parm *prdrfparm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (ph2c == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       prdrfparm = (struct readRF_parm *)rtw_zmalloc(sizeof(struct readRF_parm));
+       if (prdrfparm == NULL) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       _rtw_init_listhead(&ph2c->list);
+       ph2c->cmdcode = GEN_CMD_CODE(_GetRFReg);
+       ph2c->parmbuf = (unsigned char *)prdrfparm;
+       ph2c->cmdsz =  sizeof(struct readRF_parm);
+       ph2c->rsp = pval;
+       ph2c->rspsz = sizeof(struct readRF_rsp);
+
+       prdrfparm->offset = offset;
+
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+void rtw_getbbrfreg_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
+{
+ _func_enter_;
+
+       kfree(pcmd->parmbuf);
+       kfree(pcmd);
+
+       if (padapter->registrypriv.mp_mode == 1)
+               padapter->mppriv.workparam.bcompleted = true;
+_func_exit_;
+}
+
+void rtw_readtssi_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
+{
+ _func_enter_;
+
+       kfree(pcmd->parmbuf);
+       kfree(pcmd);
+
+       if (padapter->registrypriv.mp_mode == 1)
+               padapter->mppriv.workparam.bcompleted = true;
+_func_exit_;
+}
+
+u8 rtw_createbss_cmd(struct adapter  *padapter)
+{
+       struct cmd_obj *pcmd;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct wlan_bssid_ex *pdev_network = &padapter->registrypriv.dev_network;
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       rtw_led_control(padapter, LED_CTL_START_TO_LINK);
+
+       if (pmlmepriv->assoc_ssid.SsidLength == 0)
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for Any SSid:%s\n", pmlmepriv->assoc_ssid.Ssid));
+       else
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid));
+
+       pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (pcmd == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       _rtw_init_listhead(&pcmd->list);
+       pcmd->cmdcode = _CreateBss_CMD_;
+       pcmd->parmbuf = (unsigned char *)pdev_network;
+       pcmd->cmdsz = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network);
+       pcmd->rsp = NULL;
+       pcmd->rspsz = 0;
+       pdev_network->Length = pcmd->cmdsz;
+       res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+u8 rtw_createbss_cmd_ex(struct adapter  *padapter, unsigned char *pbss, unsigned int sz)
+{
+       struct cmd_obj *pcmd;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (pcmd == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       _rtw_init_listhead(&pcmd->list);
+       pcmd->cmdcode = GEN_CMD_CODE(_CreateBss);
+       pcmd->parmbuf = pbss;
+       pcmd->cmdsz =  sz;
+       pcmd->rsp = NULL;
+       pcmd->rspsz = 0;
+
+       res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+u8 rtw_joinbss_cmd(struct adapter  *padapter, struct wlan_network *pnetwork)
+{
+       u8      res = _SUCCESS;
+       uint    t_len = 0;
+       struct wlan_bssid_ex            *psecnetwork;
+       struct cmd_obj          *pcmd;
+       struct cmd_priv         *pcmdpriv = &padapter->cmdpriv;
+       struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
+       struct qos_priv         *pqospriv = &pmlmepriv->qospriv;
+       struct security_priv    *psecuritypriv = &padapter->securitypriv;
+       struct registry_priv    *pregistrypriv = &padapter->registrypriv;
+       struct ht_priv          *phtpriv = &pmlmepriv->htpriv;
+       enum ndis_802_11_network_infra ndis_network_mode = pnetwork->network.InfrastructureMode;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info    *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+_func_enter_;
+
+       rtw_led_control(padapter, LED_CTL_START_TO_LINK);
+
+       if (pmlmepriv->assoc_ssid.SsidLength == 0) {
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+Join cmd: Any SSid\n"));
+       } else {
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+Join cmd: SSid =[%s]\n", pmlmepriv->assoc_ssid.Ssid));
+       }
+
+       pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (pcmd == NULL) {
+               res = _FAIL;
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd: memory allocate for cmd_obj fail!!!\n"));
+               goto exit;
+       }
+       /* for IEs is fix buf size */
+       t_len = sizeof(struct wlan_bssid_ex);
+
+
+       /* for hidden ap to set fw_state here */
+       if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE)) {
+               switch (ndis_network_mode) {
+               case Ndis802_11IBSS:
+                       set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+                       break;
+               case Ndis802_11Infrastructure:
+                       set_fwstate(pmlmepriv, WIFI_STATION_STATE);
+                       break;
+               case Ndis802_11APMode:
+               case Ndis802_11AutoUnknown:
+               case Ndis802_11InfrastructureMax:
+                       break;
+               }
+       }
+
+       psecnetwork = (struct wlan_bssid_ex *)&psecuritypriv->sec_bss;
+       if (psecnetwork == NULL) {
+               if (pcmd != NULL)
+                       kfree(pcmd);
+
+               res = _FAIL;
+
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd :psecnetwork == NULL!!!\n"));
+
+               goto exit;
+       }
+
+       _rtw_memset(psecnetwork, 0, t_len);
+
+       memcpy(psecnetwork, &pnetwork->network, get_wlan_bssid_ex_sz(&pnetwork->network));
+
+       psecuritypriv->authenticator_ie[0] = (unsigned char)psecnetwork->IELength;
+
+       if ((psecnetwork->IELength-12) < (256-1)) {
+               memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], psecnetwork->IELength-12);
+       } else {
+               memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], (256-1));
+       }
+
+       psecnetwork->IELength = 0;
+       /*  Added by Albert 2009/02/18 */
+       /*  If the the driver wants to use the bssid to create the connection. */
+       /*  If not,  we have to copy the connecting AP's MAC address to it so that */
+       /*  the driver just has the bssid information for PMKIDList searching. */
+
+       if (!pmlmepriv->assoc_by_bssid)
+               memcpy(&pmlmepriv->assoc_bssid[0], &pnetwork->network.MacAddress[0], ETH_ALEN);
+
+       psecnetwork->IELength = rtw_restruct_sec_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength);
+
+
+       pqospriv->qos_option = 0;
+
+       if (pregistrypriv->wmm_enable) {
+               u32 tmp_len;
+
+               tmp_len = rtw_restruct_wmm_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength, psecnetwork->IELength);
+
+               if (psecnetwork->IELength != tmp_len) {
+                       psecnetwork->IELength = tmp_len;
+                       pqospriv->qos_option = 1; /* There is WMM IE in this corresp. beacon */
+               } else {
+                       pqospriv->qos_option = 0;/* There is no WMM IE in this corresp. beacon */
+               }
+       }
+
+       phtpriv->ht_option = false;
+       if (pregistrypriv->ht_enable) {
+               /*      Added by Albert 2010/06/23 */
+               /*      For the WEP mode, we will use the bg mode to do the connection to avoid some IOT issue. */
+               /*      Especially for Realtek 8192u SoftAP. */
+               if ((padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_) &&
+                   (padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_) &&
+                   (padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_)) {
+                       /* rtw_restructure_ht_ie */
+                       rtw_restructure_ht_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0],
+                                                                       pnetwork->network.IELength, &psecnetwork->IELength);
+               }
+       }
+
+       pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->network.IEs, pnetwork->network.IELength);
+
+       if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_TENDA)
+               padapter->pwrctrlpriv.smart_ps = 0;
+       else
+               padapter->pwrctrlpriv.smart_ps = padapter->registrypriv.smart_ps;
+
+       DBG_88E("%s: smart_ps =%d\n", __func__, padapter->pwrctrlpriv.smart_ps);
+
+       pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork);/* get cmdsz before endian conversion */
+
+       _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:
+
+_func_exit_;
+
+       return res;
+}
+
+u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue) /* for sta_mode */
+{
+       struct cmd_obj *cmdobj = NULL;
+       struct disconnect_parm *param = NULL;
+       struct cmd_priv *cmdpriv = &padapter->cmdpriv;
+       u8 res = _SUCCESS;
+
+_func_enter_;
+
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_disassoc_cmd\n"));
+
+       /* 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 (enqueue) {
+               /* need enqueue, prepare cmd_obj and enqueue */
+               cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj));
+               if (cmdobj == NULL) {
+                       res = _FAIL;
+                       kfree(param);
+                       goto exit;
+               }
+               init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_);
+               res = rtw_enqueue_cmd(cmdpriv, cmdobj);
+       } else {
+               /* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+               if (H2C_SUCCESS != disconnect_hdl(padapter, (u8 *)param))
+                       res = _FAIL;
+               kfree(param);
+       }
+
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+u8 rtw_setopmode_cmd(struct adapter  *padapter, enum ndis_802_11_network_infra networktype)
+{
+       struct  cmd_obj *ph2c;
+       struct  setopmode_parm *psetop;
+
+       struct  cmd_priv   *pcmdpriv = &padapter->cmdpriv;
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (ph2c == NULL) {
+               res = false;
+               goto exit;
+       }
+       psetop = (struct setopmode_parm *)rtw_zmalloc(sizeof(struct setopmode_parm));
+
+       if (psetop == NULL) {
+               kfree(ph2c);
+               res = false;
+               goto exit;
+       }
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
+       psetop->mode = (u8)networktype;
+
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key)
+{
+       struct cmd_obj *ph2c;
+       struct set_stakey_parm *psetstakey_para;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       struct set_stakey_rsp *psetstakey_rsp = NULL;
+
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct sta_info *sta = (struct sta_info *)psta;
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       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) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       psetstakey_rsp = (struct set_stakey_rsp *)rtw_zmalloc(sizeof(struct set_stakey_rsp));
+       if (psetstakey_rsp == NULL) {
+               kfree(ph2c);
+               kfree(psetstakey_para);
+               res = _FAIL;
+               goto exit;
+       }
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+       ph2c->rsp = (u8 *)psetstakey_rsp;
+       ph2c->rspsz = sizeof(struct set_stakey_rsp);
+
+       memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
+
+       if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+               psetstakey_para->algorithm = (unsigned char) psecuritypriv->dot11PrivacyAlgrthm;
+       else
+               GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, false);
+
+       if (unicast_key)
+               memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16);
+       else
+               memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16);
+
+       /* jeff: set this becasue at least sw key is ready */
+       padapter->securitypriv.busetkipkey = true;
+
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+u8 rtw_clearstakey_cmd(struct adapter *padapter, u8 *psta, u8 entry, u8 enqueue)
+{
+       struct cmd_obj *ph2c;
+       struct set_stakey_parm  *psetstakey_para;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       struct set_stakey_rsp *psetstakey_rsp = NULL;
+       struct sta_info *sta = (struct sta_info *)psta;
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       if (!enqueue) {
+               clear_cam_entry(padapter, entry);
+       } 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) {
+                       kfree(ph2c);
+                       res = _FAIL;
+                       goto exit;
+               }
+
+               psetstakey_rsp = (struct set_stakey_rsp *)rtw_zmalloc(sizeof(struct set_stakey_rsp));
+               if (psetstakey_rsp == NULL) {
+                       kfree(ph2c);
+                       kfree(psetstakey_para);
+                       res = _FAIL;
+                       goto exit;
+               }
+
+               init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+               ph2c->rsp = (u8 *)psetstakey_rsp;
+               ph2c->rspsz = sizeof(struct set_stakey_rsp);
+
+               memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
+
+               psetstakey_para->algorithm = _NO_PRIVACY_;
+
+               psetstakey_para->id = entry;
+
+               res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+       }
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+u8 rtw_setrttbl_cmd(struct adapter  *padapter, struct setratable_parm *prate_table)
+{
+       struct cmd_obj *ph2c;
+       struct setratable_parm *psetrttblparm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8      res = _SUCCESS;
+_func_enter_;
+
+       ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (ph2c == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+       psetrttblparm = (struct setratable_parm *)rtw_zmalloc(sizeof(struct setratable_parm));
+
+       if (psetrttblparm == NULL) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable));
+
+       memcpy(psetrttblparm, prate_table, sizeof(struct setratable_parm));
+
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+       return res;
+}
+
+u8 rtw_getrttbl_cmd(struct adapter  *padapter, struct getratable_rsp *pval)
+{
+       struct cmd_obj *ph2c;
+       struct getratable_parm *pgetrttblparm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8      res = _SUCCESS;
+_func_enter_;
+
+       ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (ph2c == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+       pgetrttblparm = (struct getratable_parm *)rtw_zmalloc(sizeof(struct getratable_parm));
+
+       if (pgetrttblparm == NULL) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+/*     init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable)); */
+
+       _rtw_init_listhead(&ph2c->list);
+       ph2c->cmdcode = GEN_CMD_CODE(_GetRaTable);
+       ph2c->parmbuf = (unsigned char *)pgetrttblparm;
+       ph2c->cmdsz =  sizeof(struct getratable_parm);
+       ph2c->rsp = (u8 *)pval;
+       ph2c->rspsz = sizeof(struct getratable_rsp);
+
+       pgetrttblparm->rsvd = 0x0;
+
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+       return res;
+}
+
+u8 rtw_setassocsta_cmd(struct adapter  *padapter, u8 *mac_addr)
+{
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       struct cmd_obj *ph2c;
+       struct set_assocsta_parm *psetassocsta_para;
+       struct set_stakey_rsp *psetassocsta_rsp = NULL;
+
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (ph2c == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       psetassocsta_para = (struct set_assocsta_parm *)rtw_zmalloc(sizeof(struct set_assocsta_parm));
+       if (psetassocsta_para == NULL) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       psetassocsta_rsp = (struct set_stakey_rsp *)rtw_zmalloc(sizeof(struct set_assocsta_rsp));
+       if (psetassocsta_rsp == NULL) {
+               kfree(ph2c);
+               kfree(psetassocsta_para);
+               return _FAIL;
+       }
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, psetassocsta_para, _SetAssocSta_CMD_);
+       ph2c->rsp = (u8 *)psetassocsta_rsp;
+       ph2c->rspsz = sizeof(struct set_assocsta_rsp);
+
+       memcpy(psetassocsta_para->addr, mac_addr, ETH_ALEN);
+
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+       return res;
+ }
+
+u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr)
+{
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       struct cmd_obj *ph2c;
+       struct addBaReq_parm *paddbareq_parm;
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       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) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       paddbareq_parm->tid = tid;
+       memcpy(paddbareq_parm->addr, addr, ETH_ALEN);
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq));
+
+       /* DBG_88E("rtw_addbareq_cmd, tid =%d\n", tid); */
+
+       /* rtw_enqueue_cmd(pcmdpriv, ph2c); */
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter)
+{
+       struct cmd_obj *ph2c;
+       struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (ph2c == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+       if (pdrvextra_cmd_parm == NULL) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID;
+       pdrvextra_cmd_parm->type_size = 0;
+       pdrvextra_cmd_parm->pbuf = (u8 *)padapter;
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+
+       /* rtw_enqueue_cmd(pcmdpriv, ph2c); */
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+       return res;
+}
+
+u8 rtw_set_ch_cmd(struct adapter *padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue)
+{
+       struct cmd_obj *pcmdobj;
+       struct set_ch_parm *set_ch_parm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+       u8 res = _SUCCESS;
+
+_func_enter_;
+
+       DBG_88E(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n",
+               FUNC_NDEV_ARG(padapter->pnetdev), ch, bw, ch_offset);
+
+       /* check input parameter */
+
+       /* prepare cmd parameter */
+       set_ch_parm = (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) {
+                       kfree(set_ch_parm);
+                       res = _FAIL;
+                       goto exit;
+               }
+
+               init_h2fwcmd_w_parm_no_rsp(pcmdobj, set_ch_parm, GEN_CMD_CODE(_SetChannel));
+               res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+       } else {
+               /* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+               if (H2C_SUCCESS != set_ch_hdl(padapter, (u8 *)set_ch_parm))
+                       res = _FAIL;
+
+               kfree(set_ch_parm);
+       }
+
+       /* do something based on res... */
+
+exit:
+
+       DBG_88E(FUNC_NDEV_FMT" res:%u\n", FUNC_NDEV_ARG(padapter->pnetdev), res);
+
+_func_exit_;
+
+       return res;
+}
+
+u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue)
+{
+       struct  cmd_obj *pcmdobj;
+       struct  SetChannelPlan_param *setChannelPlan_param;
+       struct  cmd_priv   *pcmdpriv = &padapter->cmdpriv;
+
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_chplan_cmd\n"));
+
+       /* check input parameter */
+       if (!rtw_is_channel_plan_valid(chplan)) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       /* prepare cmd parameter */
+       setChannelPlan_param = (struct  SetChannelPlan_param *)rtw_zmalloc(sizeof(struct SetChannelPlan_param));
+       if (setChannelPlan_param == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+       setChannelPlan_param->channel_plan = chplan;
+
+       if (enqueue) {
+               /* need enqueue, prepare cmd_obj and enqueue */
+               pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct   cmd_obj));
+               if (pcmdobj == NULL) {
+                       kfree(setChannelPlan_param);
+                       res = _FAIL;
+                       goto exit;
+               }
+
+               init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelPlan_param, GEN_CMD_CODE(_SetChannelPlan));
+               res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+       } else {
+               /* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+               if (H2C_SUCCESS != set_chplan_hdl(padapter, (unsigned char *)setChannelPlan_param))
+                       res = _FAIL;
+
+               kfree(setChannelPlan_param);
+       }
+
+       /* do something based on res... */
+       if (res == _SUCCESS)
+               padapter->mlmepriv.ChannelPlan = chplan;
+
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+u8 rtw_led_blink_cmd(struct adapter *padapter, struct LED_871x *pLed)
+{
+       struct  cmd_obj *pcmdobj;
+       struct  LedBlink_param *ledBlink_param;
+       struct  cmd_priv   *pcmdpriv = &padapter->cmdpriv;
+
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_led_blink_cmd\n"));
+
+       pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct   cmd_obj));
+       if (pcmdobj == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       ledBlink_param = (struct        LedBlink_param *)rtw_zmalloc(sizeof(struct      LedBlink_param));
+       if (ledBlink_param == NULL) {
+               kfree(pcmdobj);
+               res = _FAIL;
+               goto exit;
+       }
+
+       ledBlink_param->pLed = pLed;
+
+       init_h2fwcmd_w_parm_no_rsp(pcmdobj, ledBlink_param, GEN_CMD_CODE(_LedBlink));
+       res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+u8 rtw_set_csa_cmd(struct adapter *padapter, u8 new_ch_no)
+{
+       struct  cmd_obj *pcmdobj;
+       struct  SetChannelSwitch_param *setChannelSwitch_param;
+       struct  cmd_priv   *pcmdpriv = &padapter->cmdpriv;
+
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_csa_cmd\n"));
+
+       pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct   cmd_obj));
+       if (pcmdobj == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       setChannelSwitch_param = (struct SetChannelSwitch_param *)rtw_zmalloc(sizeof(struct     SetChannelSwitch_param));
+       if (setChannelSwitch_param == NULL) {
+               kfree(pcmdobj);
+               res = _FAIL;
+               goto exit;
+       }
+
+       setChannelSwitch_param->new_ch_no = new_ch_no;
+
+       init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelSwitch_param, GEN_CMD_CODE(_SetChannelSwitch));
+       res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+u8 rtw_tdls_cmd(struct adapter *padapter, u8 *addr, u8 option)
+{
+       return _SUCCESS;
+}
+
+static void traffic_status_watchdog(struct adapter *padapter)
+{
+       u8      bEnterPS;
+       u8      bBusyTraffic = false, bTxBusyTraffic = false, bRxBusyTraffic = false;
+       u8      bHigherBusyTraffic = false, bHigherBusyRxTraffic = false, bHigherBusyTxTraffic = false;
+       struct mlme_priv                *pmlmepriv = &(padapter->mlmepriv);
+
+       /*  */
+       /*  Determine if our traffic is busy now */
+       /*  */
+       if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+               if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 100 ||
+                   pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 100) {
+                       bBusyTraffic = true;
+
+                       if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
+                               bRxBusyTraffic = true;
+                       else
+                               bTxBusyTraffic = true;
+               }
+
+               /*  Higher Tx/Rx data. */
+               if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 ||
+                   pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000) {
+                       bHigherBusyTraffic = true;
+
+                       if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
+                               bHigherBusyRxTraffic = true;
+                       else
+                               bHigherBusyTxTraffic = true;
+               }
+
+               /*  check traffic for  powersaving. */
+               if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) ||
+                   (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2))
+                       bEnterPS = false;
+               else
+                       bEnterPS = true;
+
+               /*  LeisurePS only work in infra mode. */
+               if (bEnterPS)
+                       LPS_Enter(padapter);
+               else
+                       LPS_Leave(padapter);
+       } else {
+               LPS_Leave(padapter);
+       }
+
+       pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0;
+       pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0;
+       pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0;
+       pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic;
+       pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic;
+       pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic;
+       pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic;
+       pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic;
+       pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic;
+}
+
+void dynamic_chk_wk_hdl(struct adapter *padapter, u8 *pbuf, int sz)
+{
+       struct mlme_priv *pmlmepriv;
+
+       padapter = (struct adapter *)pbuf;
+       pmlmepriv = &(padapter->mlmepriv);
+
+#ifdef CONFIG_88EU_AP_MODE
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)
+               expire_timeout_chk(padapter);
+#endif
+
+       rtw_hal_sreset_xmit_status_check(padapter);
+
+       linked_status_chk(padapter);
+       traffic_status_watchdog(padapter);
+
+       rtw_hal_dm_watchdog(padapter);
+}
+
+static void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type)
+{
+       struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+       struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+       u8      mstatus;
+
+_func_enter_;
+
+       if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) ||
+           (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true))
+               return;
+
+       switch (lps_ctrl_type) {
+       case LPS_CTRL_SCAN:
+               if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+                       /* connect */
+                       LPS_Leave(padapter);
+               }
+               break;
+       case LPS_CTRL_JOINBSS:
+               LPS_Leave(padapter);
+               break;
+       case LPS_CTRL_CONNECT:
+               mstatus = 1;/* connect */
+               /*  Reset LPS Setting */
+               padapter->pwrctrlpriv.LpsIdleCount = 0;
+               rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
+               break;
+       case LPS_CTRL_DISCONNECT:
+               mstatus = 0;/* disconnect */
+               LPS_Leave(padapter);
+               rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
+               break;
+       case LPS_CTRL_SPECIAL_PACKET:
+               /* DBG_88E("LPS_CTRL_SPECIAL_PACKET\n"); */
+               pwrpriv->DelayLPSLastTimeStamp = rtw_get_current_time();
+               LPS_Leave(padapter);
+               break;
+       case LPS_CTRL_LEAVE:
+               LPS_Leave(padapter);
+               break;
+       default:
+               break;
+       }
+
+_func_exit_;
+}
+
+u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue)
+{
+       struct cmd_obj  *ph2c;
+       struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       /* struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; */
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       /* 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) {
+                       kfree(ph2c);
+                       res = _FAIL;
+                       goto exit;
+               }
+
+               pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID;
+               pdrvextra_cmd_parm->type_size = lps_ctrl_type;
+               pdrvextra_cmd_parm->pbuf = NULL;
+
+               init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+               res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+       } else {
+               lps_ctrl_wk_hdl(padapter, lps_ctrl_type);
+       }
+
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+static void rpt_timer_setting_wk_hdl(struct adapter *padapter, u16 min_time)
+{
+       rtw_hal_set_hwreg(padapter, HW_VAR_RPT_TIMER_SETTING, (u8 *)(&min_time));
+}
+
+u8 rtw_rpt_timer_cfg_cmd(struct adapter *padapter, u16 min_time)
+{
+       struct cmd_obj          *ph2c;
+       struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+       u8      res = _SUCCESS;
+
+_func_enter_;
+       ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (ph2c == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+       if (pdrvextra_cmd_parm == NULL) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm->ec_id = RTP_TIMER_CFG_WK_CID;
+       pdrvextra_cmd_parm->type_size = min_time;
+       pdrvextra_cmd_parm->pbuf = NULL;
+       init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+static void antenna_select_wk_hdl(struct adapter *padapter, u8 antenna)
+{
+       rtw_hal_set_hwreg(padapter, HW_VAR_ANTENNA_DIVERSITY_SELECT, (u8 *)(&antenna));
+}
+
+u8 rtw_antenna_select_cmd(struct adapter *padapter, u8 antenna, u8 enqueue)
+{
+       struct cmd_obj          *ph2c;
+       struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8      support_ant_div;
+       u8      res = _SUCCESS;
+
+_func_enter_;
+       rtw_hal_get_def_var(padapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &support_ant_div);
+       if (!support_ant_div)
+               return res;
+
+       if (enqueue) {
+               ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+               if (ph2c == NULL) {
+                       res = _FAIL;
+                       goto exit;
+               }
+
+               pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+               if (pdrvextra_cmd_parm == NULL) {
+                       kfree(ph2c);
+                       res = _FAIL;
+                       goto exit;
+               }
+
+               pdrvextra_cmd_parm->ec_id = ANT_SELECT_WK_CID;
+               pdrvextra_cmd_parm->type_size = antenna;
+               pdrvextra_cmd_parm->pbuf = NULL;
+               init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+               res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+       } else {
+               antenna_select_wk_hdl(padapter, antenna);
+       }
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+static void power_saving_wk_hdl(struct adapter *padapter, u8 *pbuf, int sz)
+{
+        rtw_ps_processor(padapter);
+}
+
+#ifdef CONFIG_88EU_P2P
+u8 p2p_protocol_wk_cmd(struct adapter *padapter, int intCmdType)
+{
+       struct cmd_obj  *ph2c;
+       struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
+       struct wifidirect_info  *pwdinfo = &(padapter->wdinfo);
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8      res = _SUCCESS;
+
+_func_enter_;
+
+       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) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm->ec_id = P2P_PROTO_WK_CID;
+       pdrvextra_cmd_parm->type_size = intCmdType;     /*      As the command tppe. */
+       pdrvextra_cmd_parm->pbuf = NULL;                /*      Must be NULL here */
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+       return res;
+}
+#endif /* CONFIG_88EU_P2P */
+
+u8 rtw_ps_cmd(struct adapter *padapter)
+{
+       struct cmd_obj          *ppscmd;
+       struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+       u8      res = _SUCCESS;
+_func_enter_;
+
+       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) {
+               kfree(ppscmd);
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID;
+       pdrvextra_cmd_parm->pbuf = NULL;
+       init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+       res = rtw_enqueue_cmd(pcmdpriv, ppscmd);
+
+exit:
+
+_func_exit_;
+
+       return res;
+}
+
+#ifdef CONFIG_88EU_AP_MODE
+
+static void rtw_chk_hi_queue_hdl(struct adapter *padapter)
+{
+       int cnt = 0;
+       struct sta_info *psta_bmc;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+
+       psta_bmc = rtw_get_bcmc_stainfo(padapter);
+       if (!psta_bmc)
+               return;
+
+       if (psta_bmc->sleepq_len == 0) {
+               u8 val = 0;
+
+               /* while ((rtw_read32(padapter, 0x414)&0x00ffff00)!= 0) */
+               /* while ((rtw_read32(padapter, 0x414)&0x0000ff00)!= 0) */
+
+               rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val);
+
+               while (!val) {
+                       rtw_msleep_os(100);
+
+                       cnt++;
+
+                       if (cnt > 10)
+                               break;
+
+                       rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val);
+               }
+
+               if (cnt <= 10) {
+                       pstapriv->tim_bitmap &= ~BIT(0);
+                       pstapriv->sta_dz_bitmap &= ~BIT(0);
+
+                       update_beacon(padapter, _TIM_IE_, NULL, false);
+               } else { /* re check again */
+                       rtw_chk_hi_queue_cmd(padapter);
+               }
+       }
+}
+
+u8 rtw_chk_hi_queue_cmd(struct adapter *padapter)
+{
+       struct cmd_obj  *ph2c;
+       struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8      res = _SUCCESS;
+
+       ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (ph2c == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+       if (pdrvextra_cmd_parm == NULL) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID;
+       pdrvextra_cmd_parm->type_size = 0;
+       pdrvextra_cmd_parm->pbuf = NULL;
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+       return res;
+}
+#endif
+
+u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt)
+{
+       struct cmd_obj *ph2c;
+       struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8      res = _SUCCESS;
+
+       ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+       if (ph2c == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+       if (pdrvextra_cmd_parm == NULL) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm->ec_id = C2H_WK_CID;
+       pdrvextra_cmd_parm->type_size = c2h_evt ? 16 : 0;
+       pdrvextra_cmd_parm->pbuf = c2h_evt;
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+       res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+       return res;
+}
+
+static s32 c2h_evt_hdl(struct adapter *adapter, struct c2h_evt_hdr *c2h_evt, c2h_id_filter filter)
+{
+       s32 ret = _FAIL;
+       u8 buf[16];
+
+       if (!c2h_evt) {
+               /* No c2h event in cmd_obj, read c2h event before handling*/
+               if (c2h_evt_read(adapter, buf) == _SUCCESS) {
+                       c2h_evt = (struct c2h_evt_hdr *)buf;
+
+                       if (filter && filter(c2h_evt->id) == false)
+                               goto exit;
+
+                       ret = rtw_hal_c2h_handler(adapter, c2h_evt);
+               }
+       } else {
+               if (filter && filter(c2h_evt->id) == false)
+                       goto exit;
+
+               ret = rtw_hal_c2h_handler(adapter, c2h_evt);
+       }
+exit:
+       return ret;
+}
+
+static void c2h_wk_callback(struct work_struct *work)
+{
+       struct evt_priv *evtpriv = container_of(work, struct evt_priv, c2h_wk);
+       struct adapter *adapter = container_of(evtpriv, struct adapter, evtpriv);
+       struct c2h_evt_hdr *c2h_evt;
+       c2h_id_filter ccx_id_filter = rtw_hal_c2h_id_filter_ccx(adapter);
+
+       evtpriv->c2h_wk_alive = true;
+
+       while (!rtw_cbuf_empty(evtpriv->c2h_queue)) {
+               if ((c2h_evt = (struct c2h_evt_hdr *)rtw_cbuf_pop(evtpriv->c2h_queue)) != NULL) {
+                       /* This C2H event is read, clear it */
+                       c2h_evt_clear(adapter);
+               } else if ((c2h_evt = (struct c2h_evt_hdr *)rtw_malloc(16)) != NULL) {
+                       /* This C2H event is not read, read & clear now */
+                       if (c2h_evt_read(adapter, (u8 *)c2h_evt) != _SUCCESS)
+                               continue;
+               }
+
+               /* Special pointer to trigger c2h_evt_clear only */
+               if ((void *)c2h_evt == (void *)evtpriv)
+                       continue;
+
+               if (!c2h_evt_exist(c2h_evt)) {
+                       kfree(c2h_evt);
+                       continue;
+               }
+
+               if (ccx_id_filter(c2h_evt->id) == true) {
+                       /* Handle CCX report here */
+                       rtw_hal_c2h_handler(adapter, c2h_evt);
+                       kfree(c2h_evt);
+               } else {
+#ifdef CONFIG_88EU_P2P
+                       /* Enqueue into cmd_thread for others */
+                       rtw_c2h_wk_cmd(adapter, (u8 *)c2h_evt);
+#endif
+               }
+       }
+
+       evtpriv->c2h_wk_alive = false;
+}
+
+u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+       struct drvextra_cmd_parm *pdrvextra_cmd;
+
+       if (!pbuf)
+               return H2C_PARAMETERS_ERROR;
+
+       pdrvextra_cmd = (struct drvextra_cmd_parm *)pbuf;
+
+       switch (pdrvextra_cmd->ec_id) {
+       case DYNAMIC_CHK_WK_CID:
+               dynamic_chk_wk_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size);
+               break;
+       case POWER_SAVING_CTRL_WK_CID:
+               power_saving_wk_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size);
+               break;
+       case LPS_CTRL_WK_CID:
+               lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type_size);
+               break;
+       case RTP_TIMER_CFG_WK_CID:
+               rpt_timer_setting_wk_hdl(padapter, pdrvextra_cmd->type_size);
+               break;
+       case ANT_SELECT_WK_CID:
+               antenna_select_wk_hdl(padapter, pdrvextra_cmd->type_size);
+               break;
+#ifdef CONFIG_88EU_P2P
+       case P2P_PS_WK_CID:
+               p2p_ps_wk_hdl(padapter, pdrvextra_cmd->type_size);
+               break;
+       case P2P_PROTO_WK_CID:
+               /*      Commented by Albert 2011/07/01 */
+               /*      I used the type_size as the type command */
+               p2p_protocol_wk_hdl(padapter, pdrvextra_cmd->type_size);
+               break;
+#endif
+#ifdef CONFIG_88EU_AP_MODE
+       case CHECK_HIQ_WK_CID:
+               rtw_chk_hi_queue_hdl(padapter);
+               break;
+#endif /* CONFIG_88EU_AP_MODE */
+       case C2H_WK_CID:
+               c2h_evt_hdl(padapter, (struct c2h_evt_hdr *)pdrvextra_cmd->pbuf, NULL);
+               break;
+       default:
+               break;
+       }
+
+       if (pdrvextra_cmd->pbuf && pdrvextra_cmd->type_size > 0)
+               kfree(pdrvextra_cmd->pbuf);
+
+       return H2C_SUCCESS;
+}
+
+void rtw_survey_cmd_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
+{
+       struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+       if (pcmd->res == H2C_DROPPED) {
+               /* TODO: cancel timer and do timeout handler directly... */
+               /* need to make timeout handlerOS independent */
+               _set_timer(&pmlmepriv->scan_to_timer, 1);
+               } else if (pcmd->res != H2C_SUCCESS) {
+               _set_timer(&pmlmepriv->scan_to_timer, 1);
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ********Error: MgntActrtw_set_802_11_bssid_LIST_SCAN Fail ************\n\n."));
+       }
+
+       /*  free cmd */
+       rtw_free_cmd_obj(pcmd);
+
+_func_exit_;
+}
+void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+       unsigned long   irqL;
+       struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+       if (pcmd->res != H2C_SUCCESS) {
+               _enter_critical_bh(&pmlmepriv->lock, &irqL);
+               set_fwstate(pmlmepriv, _FW_LINKED);
+               _exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ***Error: disconnect_cmd_callback Fail ***\n."));
+
+               goto exit;
+       } else /* clear bridge database */
+               nat25_db_cleanup(padapter);
+
+       /*  free cmd */
+       rtw_free_cmd_obj(pcmd);
+
+exit:
+
+_func_exit_;
+}
+
+void rtw_joinbss_cmd_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
+{
+       struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+       if (pcmd->res == H2C_DROPPED) {
+               /* TODO: cancel timer and do timeout handler directly... */
+               /* need to make timeout handlerOS independent */
+               _set_timer(&pmlmepriv->assoc_timer, 1);
+       } else if (pcmd->res != H2C_SUCCESS) {
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("********Error:rtw_select_and_join_from_scanned_queue Wait Sema  Fail ************\n"));
+               _set_timer(&pmlmepriv->assoc_timer, 1);
+       }
+
+       rtw_free_cmd_obj(pcmd);
+
+_func_exit_;
+}
+
+void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+       unsigned long irqL;
+       u8 timer_cancelled;
+       struct sta_info *psta = NULL;
+       struct wlan_network *pwlan = NULL;
+       struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf;
+       struct wlan_network *tgt_network = &(pmlmepriv->cur_network);
+
+_func_enter_;
+
+       if ((pcmd->res != H2C_SUCCESS)) {
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ********Error: rtw_createbss_cmd_callback  Fail ************\n\n."));
+               _set_timer(&pmlmepriv->assoc_timer, 1);
+       }
+
+       _cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled);
+
+       _enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+               psta = rtw_get_stainfo(&padapter->stapriv, pnetwork->MacAddress);
+               if (!psta) {
+                       psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress);
+                       if (psta == NULL) {
+                               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nCan't alloc sta_info when createbss_cmd_callback\n"));
+                               goto createbss_cmd_fail ;
+                       }
+               }
+
+               rtw_indicate_connect(padapter);
+       } else {
+               unsigned long   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) {
+                               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n Error:  can't get pwlan in rtw_joinbss_event_callback\n"));
+                               _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);
+               }
+
+               pnetwork->Length = get_wlan_bssid_ex_sz(pnetwork);
+               memcpy(&(pwlan->network), pnetwork, pnetwork->Length);
+
+               memcpy(&tgt_network->network, pnetwork, (get_wlan_bssid_ex_sz(pnetwork)));
+
+               _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+               _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);
+
+       rtw_free_cmd_obj(pcmd);
+
+_func_exit_;
+}
+
+void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
+{
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *)(pcmd->rsp);
+       struct sta_info *psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr);
+
+_func_enter_;
+
+       if (psta == NULL) {
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nERROR: rtw_setstaKey_cmdrsp_callback => can't get sta_info\n\n"));
+               goto exit;
+       }
+exit:
+       rtw_free_cmd_obj(pcmd);
+_func_exit_;
+}
+
+void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
+{
+       unsigned long   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);
+
+_func_enter_;
+
+       if (psta == NULL) {
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nERROR: setassocsta_cmdrsp_callbac => can't get sta_info\n\n"));
+               goto exit;
+       }
+
+       psta->aid = passocsta_rsp->cam_id;
+       psta->mac_id = passocsta_rsp->cam_id;
+
+       _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);
+
+_func_exit_;
+}