linux/drivers/staging/rtl8723au/core/rtw_mlme_ext.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of version 2 of the GNU General Public License as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12 * more details.
  13 *
  14 ******************************************************************************/
  15#define _RTW_MLME_EXT_C_
  16
  17#include <osdep_service.h>
  18#include <drv_types.h>
  19#include <wifi.h>
  20#include <rtw_mlme_ext.h>
  21#include <wlan_bssdef.h>
  22#include <mlme_osdep.h>
  23#include <recv_osdep.h>
  24#include <linux/ieee80211.h>
  25#include <rtl8723a_hal.h>
  26
  27static int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  28static int OnAssocRsp23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  29static int OnProbeReq23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  30static int OnProbeRsp23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  31static int DoReserved23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  32static int OnBeacon23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  33static int OnAtim23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  34static int OnDisassoc23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  35static int OnAuth23aClient23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  36static int OnDeAuth23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  37static int OnAction23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  38
  39static int on_action_spct23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  40static int OnAction23a_qos(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  41static int OnAction23a_dls(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  42static int OnAction23a_back23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  43static int on_action_public23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  44static int OnAction23a_ht(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  45static int OnAction23a_wmm(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  46static int OnAction23a_p2p(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  47
  48static void issue_assocreq(struct rtw_adapter *padapter);
  49static void issue_probereq(struct rtw_adapter *padapter,
  50                           struct cfg80211_ssid *pssid, u8 *da);
  51static int issue_probereq_ex(struct rtw_adapter *padapter,
  52                             struct cfg80211_ssid *pssid,
  53                             u8 *da, int try_cnt, int wait_ms);
  54static void issue_probersp(struct rtw_adapter *padapter, unsigned char *da,
  55                           u8 is_valid_p2p_probereq);
  56static void issue_auth(struct rtw_adapter *padapter, struct sta_info *psta,
  57                       unsigned short status);
  58static int issue_deauth_ex(struct rtw_adapter *padapter, u8 *da,
  59                           unsigned short reason, int try_cnt, int wait_ms);
  60static void start_clnt_assoc(struct rtw_adapter *padapter);
  61static void start_clnt_auth(struct rtw_adapter *padapter);
  62static void start_clnt_join(struct rtw_adapter *padapter);
  63static void start_create_ibss(struct rtw_adapter *padapter);
  64static struct wlan_bssid_ex *collect_bss_info(struct rtw_adapter *padapter,
  65                                              struct recv_frame *precv_frame);
  66
  67#ifdef CONFIG_8723AU_AP_MODE
  68static int OnAuth23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
  69static void issue_assocrsp(struct rtw_adapter *padapter, unsigned short status,
  70                           struct sta_info *pstat, u16 pkt_type);
  71#endif
  72
  73static struct mlme_handler mlme_sta_tbl[]={
  74        {"OnAssocReq23a",               &OnAssocReq23a},
  75        {"OnAssocRsp23a",               &OnAssocRsp23a},
  76        {"OnReAssocReq",        &OnAssocReq23a},
  77        {"OnReAssocRsp",        &OnAssocRsp23a},
  78        {"OnProbeReq23a",               &OnProbeReq23a},
  79        {"OnProbeRsp23a",               &OnProbeRsp23a},
  80
  81        /*----------------------------------------------------------
  82                                        below 2 are reserved
  83        -----------------------------------------------------------*/
  84        {"DoReserved23a",               &DoReserved23a},
  85        {"DoReserved23a",               &DoReserved23a},
  86        {"OnBeacon23a",         &OnBeacon23a},
  87        {"OnATIM",              &OnAtim23a},
  88        {"OnDisassoc23a",               &OnDisassoc23a},
  89        {"OnAuth23a",           &OnAuth23aClient23a},
  90        {"OnDeAuth23a",         &OnDeAuth23a},
  91        {"OnAction23a",         &OnAction23a},
  92};
  93
  94static struct action_handler OnAction23a_tbl[]={
  95        {WLAN_CATEGORY_SPECTRUM_MGMT, "ACTION_SPECTRUM_MGMT", on_action_spct23a},
  96        {WLAN_CATEGORY_QOS, "ACTION_QOS", &OnAction23a_qos},
  97        {WLAN_CATEGORY_DLS, "ACTION_DLS", &OnAction23a_dls},
  98        {WLAN_CATEGORY_BACK, "ACTION_BACK", &OnAction23a_back23a},
  99        {WLAN_CATEGORY_PUBLIC, "ACTION_PUBLIC", on_action_public23a},
 100        {WLAN_CATEGORY_HT, "ACTION_HT", &OnAction23a_ht},
 101        {WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &DoReserved23a},
 102        {WLAN_CATEGORY_WMM, "ACTION_WMM", &OnAction23a_wmm},
 103        {WLAN_CATEGORY_VENDOR_SPECIFIC, "ACTION_P2P", &OnAction23a_p2p},
 104};
 105
 106static u8       null_addr[ETH_ALEN]= {0, 0, 0, 0, 0, 0};
 107
 108/**************************************************
 109OUI definitions for the vendor specific IE
 110***************************************************/
 111unsigned char WMM_OUI23A[] = {0x00, 0x50, 0xf2, 0x02};
 112unsigned char WPS_OUI23A[] = {0x00, 0x50, 0xf2, 0x04};
 113unsigned char P2P_OUI23A[] = {0x50, 0x6F, 0x9A, 0x09};
 114unsigned char WFD_OUI23A[] = {0x50, 0x6F, 0x9A, 0x0A};
 115
 116unsigned char WMM_INFO_OUI23A[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01};
 117unsigned char WMM_PARA_OUI23A[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
 118
 119static unsigned char REALTEK_96B_IE[] = {0x00, 0xe0, 0x4c, 0x02, 0x01, 0x20};
 120
 121/********************************************************
 122MCS rate definitions
 123*********************************************************/
 124unsigned char MCS_rate_2R23A[16] = {
 125        0xff, 0xff, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0,
 126        0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
 127unsigned char MCS_rate_1R23A[16] = {
 128        0xff, 0x00, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0,
 129        0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
 130
 131/********************************************************
 132ChannelPlan definitions
 133*********************************************************/
 134
 135static struct rt_channel_plan_2g RTW_ChannelPlan2G[RT_CHANNEL_DOMAIN_2G_MAX] = {
 136        /*  0x00, RT_CHANNEL_DOMAIN_2G_WORLD , Passive scan CH 12, 13 */
 137        {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},
 138        /*  0x01, RT_CHANNEL_DOMAIN_2G_ETSI1 */
 139        {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},
 140        /*  0x02, RT_CHANNEL_DOMAIN_2G_FCC1 */
 141        {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11},
 142        /*  0x03, RT_CHANNEL_DOMAIN_2G_MIKK1 */
 143        {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14},
 144        /*  0x04, RT_CHANNEL_DOMAIN_2G_ETSI2 */
 145        {{10, 11, 12, 13}, 4},
 146        /*  0x05, RT_CHANNEL_DOMAIN_2G_NULL */
 147        {{}, 0},
 148};
 149
 150static struct rt_channel_plan_5g RTW_ChannelPlan5G[RT_CHANNEL_DOMAIN_5G_MAX] = {
 151        /*  0x00, RT_CHANNEL_DOMAIN_5G_NULL */
 152        {{}, 0},
 153        /*  0x01, RT_CHANNEL_DOMAIN_5G_ETSI1 */
 154        {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112,
 155          116, 120, 124, 128, 132, 136, 140}, 19},
 156        /*  0x02, RT_CHANNEL_DOMAIN_5G_ETSI2 */
 157        {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112,
 158          116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}, 24},
 159        /*  0x03, RT_CHANNEL_DOMAIN_5G_ETSI3 */
 160        {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112,
 161          116, 120, 124, 128, 132, 149, 153, 157, 161, 165}, 22},
 162        /*  0x04, RT_CHANNEL_DOMAIN_5G_FCC1 */
 163        {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112,
 164          116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}, 24},
 165        /*  0x05, RT_CHANNEL_DOMAIN_5G_FCC2 */
 166        {{36, 40, 44, 48, 149, 153, 157, 161, 165}, 9},
 167        /*  0x06, RT_CHANNEL_DOMAIN_5G_FCC3 */
 168        {{36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165}, 13},
 169        /*  0x07, RT_CHANNEL_DOMAIN_5G_FCC4 */
 170        {{36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161}, 12},
 171        /*  0x08, RT_CHANNEL_DOMAIN_5G_FCC5 */
 172        {{149, 153, 157, 161, 165}, 5},
 173        /*  0x09, RT_CHANNEL_DOMAIN_5G_FCC6 */
 174        {{36, 40, 44, 48, 52, 56, 60, 64}, 8},
 175        /*  0x0A, RT_CHANNEL_DOMAIN_5G_FCC7_IC1 */
 176        {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112,
 177          116, 136, 140, 149, 153, 157, 161, 165}, 20},
 178        /*  0x0B, RT_CHANNEL_DOMAIN_5G_KCC1 */
 179        {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112,
 180          116, 120, 124, 149, 153, 157, 161, 165}, 20},
 181        /*  0x0C, RT_CHANNEL_DOMAIN_5G_MKK1 */
 182        {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112,
 183          116, 120, 124, 128, 132, 136, 140}, 19},
 184        /*  0x0D, RT_CHANNEL_DOMAIN_5G_MKK2 */
 185        {{36, 40, 44, 48, 52, 56, 60, 64}, 8},
 186        /*  0x0E, RT_CHANNEL_DOMAIN_5G_MKK3 */
 187        {{100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 11},
 188        /*  0x0F, RT_CHANNEL_DOMAIN_5G_NCC1 */
 189        {{56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149,
 190          153, 157, 161, 165}, 15},
 191        /*  0x10, RT_CHANNEL_DOMAIN_5G_NCC2 */
 192        {{56, 60, 64, 149, 153, 157, 161, 165}, 8},
 193
 194        /*  Driver self defined for old channel plan Compatible,
 195            Remember to modify if have new channel plan definition ===== */
 196        /*  0x11, RT_CHANNEL_DOMAIN_5G_FCC */
 197        {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112,
 198          116, 132, 136, 140, 149, 153, 157, 161, 165}, 21},
 199        /*  0x12, RT_CHANNEL_DOMAIN_5G_JAPAN_NO_DFS */
 200        {{36, 40, 44, 48}, 4},
 201        /*  0x13, RT_CHANNEL_DOMAIN_5G_FCC4_NO_DFS */
 202        {{36, 40, 44, 48, 149, 153, 157, 161}, 8},
 203};
 204
 205static struct rt_channel_plan_map RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = {
 206        /*  0x00 ~ 0x1F , Old Define ===== */
 207        {0x02, 0x11},   /* 0x00, RT_CHANNEL_DOMAIN_FCC */
 208        {0x02, 0x0A},   /* 0x01, RT_CHANNEL_DOMAIN_IC */
 209        {0x01, 0x01},   /* 0x02, RT_CHANNEL_DOMAIN_ETSI */
 210        {0x01, 0x00},   /* 0x03, RT_CHANNEL_DOMAIN_SPAIN */
 211        {0x01, 0x00},   /* 0x04, RT_CHANNEL_DOMAIN_FRANCE */
 212        {0x03, 0x00},   /* 0x05, RT_CHANNEL_DOMAIN_MKK */
 213        {0x03, 0x00},   /* 0x06, RT_CHANNEL_DOMAIN_MKK1 */
 214        {0x01, 0x09},   /* 0x07, RT_CHANNEL_DOMAIN_ISRAEL */
 215        {0x03, 0x09},   /* 0x08, RT_CHANNEL_DOMAIN_TELEC */
 216        {0x03, 0x00},   /* 0x09, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN */
 217        {0x00, 0x00},   /* 0x0A, RT_CHANNEL_DOMAIN_WORLD_WIDE_13 */
 218        {0x02, 0x0F},   /* 0x0B, RT_CHANNEL_DOMAIN_TAIWAN */
 219        {0x01, 0x08},   /* 0x0C, RT_CHANNEL_DOMAIN_CHINA */
 220        {0x02, 0x06},   /* 0x0D, RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO */
 221        {0x02, 0x0B},   /* 0x0E, RT_CHANNEL_DOMAIN_KOREA */
 222        {0x02, 0x09},   /* 0x0F, RT_CHANNEL_DOMAIN_TURKEY */
 223        {0x01, 0x01},   /* 0x10, RT_CHANNEL_DOMAIN_JAPAN */
 224        {0x02, 0x05},   /* 0x11, RT_CHANNEL_DOMAIN_FCC_NO_DFS */
 225        {0x01, 0x12},   /* 0x12, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */
 226        {0x00, 0x04},   /* 0x13, RT_CHANNEL_DOMAIN_WORLD_WIDE_5G */
 227        {0x02, 0x10},   /* 0x14, RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS */
 228        {0x00, 0x12},   /* 0x15, RT_CHANNEL_DOMAIN_ETSI_NO_DFS */
 229        {0x00, 0x13},   /* 0x16, RT_CHANNEL_DOMAIN_KOREA_NO_DFS */
 230        {0x03, 0x12},   /* 0x17, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */
 231        {0x05, 0x08},   /* 0x18, RT_CHANNEL_DOMAIN_PAKISTAN_NO_DFS */
 232        {0x02, 0x08},   /* 0x19, RT_CHANNEL_DOMAIN_TAIWAN2_NO_DFS */
 233        {0x00, 0x00},   /* 0x1A, */
 234        {0x00, 0x00},   /* 0x1B, */
 235        {0x00, 0x00},   /* 0x1C, */
 236        {0x00, 0x00},   /* 0x1D, */
 237        {0x00, 0x00},   /* 0x1E, */
 238        {0x05, 0x04},   /* 0x1F, RT_CHANNEL_DOMAIN_WORLD_WIDE_ONLY_5G */
 239        /*  0x20 ~ 0x7F , New Define ===== */
 240        {0x00, 0x00},   /* 0x20, RT_CHANNEL_DOMAIN_WORLD_NULL */
 241        {0x01, 0x00},   /* 0x21, RT_CHANNEL_DOMAIN_ETSI1_NULL */
 242        {0x02, 0x00},   /* 0x22, RT_CHANNEL_DOMAIN_FCC1_NULL */
 243        {0x03, 0x00},   /* 0x23, RT_CHANNEL_DOMAIN_MKK1_NULL */
 244        {0x04, 0x00},   /* 0x24, RT_CHANNEL_DOMAIN_ETSI2_NULL */
 245        {0x02, 0x04},   /* 0x25, RT_CHANNEL_DOMAIN_FCC1_FCC1 */
 246        {0x00, 0x01},   /* 0x26, RT_CHANNEL_DOMAIN_WORLD_ETSI1 */
 247        {0x03, 0x0C},   /* 0x27, RT_CHANNEL_DOMAIN_MKK1_MKK1 */
 248        {0x00, 0x0B},   /* 0x28, RT_CHANNEL_DOMAIN_WORLD_KCC1 */
 249        {0x00, 0x05},   /* 0x29, RT_CHANNEL_DOMAIN_WORLD_FCC2 */
 250        {0x00, 0x00},   /* 0x2A, */
 251        {0x00, 0x00},   /* 0x2B, */
 252        {0x00, 0x00},   /* 0x2C, */
 253        {0x00, 0x00},   /* 0x2D, */
 254        {0x00, 0x00},   /* 0x2E, */
 255        {0x00, 0x00},   /* 0x2F, */
 256        {0x00, 0x06},   /* 0x30, RT_CHANNEL_DOMAIN_WORLD_FCC3 */
 257        {0x00, 0x07},   /* 0x31, RT_CHANNEL_DOMAIN_WORLD_FCC4 */
 258        {0x00, 0x08},   /* 0x32, RT_CHANNEL_DOMAIN_WORLD_FCC5 */
 259        {0x00, 0x09},   /* 0x33, RT_CHANNEL_DOMAIN_WORLD_FCC6 */
 260        {0x02, 0x0A},   /* 0x34, RT_CHANNEL_DOMAIN_FCC1_FCC7 */
 261        {0x00, 0x02},   /* 0x35, RT_CHANNEL_DOMAIN_WORLD_ETSI2 */
 262        {0x00, 0x03},   /* 0x36, RT_CHANNEL_DOMAIN_WORLD_ETSI3 */
 263        {0x03, 0x0D},   /* 0x37, RT_CHANNEL_DOMAIN_MKK1_MKK2 */
 264        {0x03, 0x0E},   /* 0x38, RT_CHANNEL_DOMAIN_MKK1_MKK3 */
 265        {0x02, 0x0F},   /* 0x39, RT_CHANNEL_DOMAIN_FCC1_NCC1 */
 266        {0x00, 0x00},   /* 0x3A, */
 267        {0x00, 0x00},   /* 0x3B, */
 268        {0x00, 0x00},   /* 0x3C, */
 269        {0x00, 0x00},   /* 0x3D, */
 270        {0x00, 0x00},   /* 0x3E, */
 271        {0x00, 0x00},   /* 0x3F, */
 272        {0x02, 0x10},   /* 0x40, RT_CHANNEL_DOMAIN_FCC1_NCC2 */
 273        {0x03, 0x00},   /* 0x41, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G */
 274};
 275
 276static struct rt_channel_plan_map RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE =
 277{0x03, 0x02}; /* use the conbination for max channel numbers */
 278
 279static void dummy_event_callback(struct rtw_adapter *adapter, const u8 *pbuf)
 280{
 281}
 282
 283static struct fwevent wlanevents[] =
 284{
 285        {0, &dummy_event_callback},     /*0*/
 286        {0, NULL},
 287        {0, NULL},
 288        {0, NULL},
 289        {0, NULL},
 290        {0, NULL},
 291        {0, NULL},
 292        {0, NULL},
 293        {0, &rtw_survey_event_cb23a},           /*8*/
 294        {sizeof (struct surveydone_event), &rtw_surveydone_event_callback23a},
 295        {0, &rtw23a_joinbss_event_cb},          /*10*/
 296        {sizeof(struct stassoc_event), &rtw_stassoc_event_callback23a},
 297        {sizeof(struct stadel_event), &rtw_stadel_event_callback23a},
 298        {0, &dummy_event_callback},
 299        {0, &dummy_event_callback},
 300        {0, NULL},      /*15*/
 301        {0, NULL},
 302        {0, NULL},
 303        {0, NULL},
 304        {0, &dummy_event_callback},
 305        {0, NULL},       /*20*/
 306        {0, NULL},
 307        {0, NULL},
 308        {0, &dummy_event_callback},
 309        {0, NULL},
 310};
 311
 312
 313static void rtw_correct_TSF(struct rtw_adapter *padapter)
 314{
 315        hw_var_set_correct_tsf(padapter);
 316}
 317
 318static void
 319rtw_update_TSF(struct mlme_ext_priv *pmlmeext, struct ieee80211_mgmt *mgmt)
 320{
 321        pmlmeext->TSFValue = get_unaligned_le64(&mgmt->u.beacon.timestamp);
 322}
 323
 324/*
 325 * Search the @param channel_num in given @param channel_set
 326 * @ch_set: the given channel set
 327 * @ch: the given channel number
 328 *
 329 * return the index of channel_num in channel_set, -1 if not found
 330 */
 331int rtw_ch_set_search_ch23a(struct rt_channel_info *ch_set, const u32 ch)
 332{
 333        int i;
 334
 335        for (i = 0; ch_set[i]. ChannelNum != 0; i++) {
 336                if (ch == ch_set[i].ChannelNum)
 337                        break;
 338        }
 339
 340        if (i >= ch_set[i].ChannelNum)
 341                return -1;
 342        return i;
 343}
 344
 345/****************************************************************************
 346
 347Following are the initialization functions for WiFi MLME
 348
 349*****************************************************************************/
 350
 351int init_hw_mlme_ext23a(struct rtw_adapter *padapter)
 352{
 353        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
 354
 355        set_channel_bwmode23a(padapter, pmlmeext->cur_channel,
 356                              pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
 357        return _SUCCESS;
 358}
 359
 360static void init_mlme_ext_priv23a_value(struct rtw_adapter *padapter)
 361{
 362        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
 363        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
 364        unsigned char   mixed_datarate[NumRates] = {
 365                _1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_,
 366                _9M_RATE_, _12M_RATE_, _18M_RATE_, _24M_RATE_, _36M_RATE_,
 367                _48M_RATE_, _54M_RATE_, 0xff};
 368        unsigned char   mixed_basicrate[NumRates] = {
 369                _1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_,
 370                _12M_RATE_, _24M_RATE_, 0xff,};
 371
 372        atomic_set(&pmlmeext->event_seq, 0);
 373        /* reset to zero when disconnect at client mode */
 374        pmlmeext->mgnt_seq = 0;
 375
 376        pmlmeext->cur_channel = padapter->registrypriv.channel;
 377        pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
 378        pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
 379
 380        pmlmeext->retry = 0;
 381
 382        pmlmeext->cur_wireless_mode = padapter->registrypriv.wireless_mode;
 383
 384        memcpy(pmlmeext->datarate, mixed_datarate, NumRates);
 385        memcpy(pmlmeext->basicrate, mixed_basicrate, NumRates);
 386
 387        if (pmlmeext->cur_channel > 14)
 388                pmlmeext->tx_rate = IEEE80211_OFDM_RATE_6MB;
 389        else
 390                pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB;
 391
 392        pmlmeext->sitesurvey_res.state = SCAN_DISABLE;
 393        pmlmeext->sitesurvey_res.channel_idx = 0;
 394        pmlmeext->sitesurvey_res.bss_cnt = 0;
 395        pmlmeext->scan_abort = false;
 396
 397        pmlmeinfo->state = MSR_NOLINK;
 398        pmlmeinfo->reauth_count = 0;
 399        pmlmeinfo->reassoc_count = 0;
 400        pmlmeinfo->link_count = 0;
 401        pmlmeinfo->auth_seq = 0;
 402        pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open;
 403        pmlmeinfo->key_index = 0;
 404        pmlmeinfo->iv = 0;
 405
 406        pmlmeinfo->enc_algo = 0;
 407        pmlmeinfo->authModeToggle = 0;
 408
 409        memset(pmlmeinfo->chg_txt, 0, 128);
 410
 411        pmlmeinfo->slotTime = SHORT_SLOT_TIME;
 412        pmlmeinfo->preamble_mode = PREAMBLE_AUTO;
 413
 414        pmlmeinfo->dialogToken = 0;
 415
 416        pmlmeext->action_public_rxseq = 0xffff;
 417        pmlmeext->action_public_dialog_token = 0xff;
 418}
 419
 420static int has_channel(struct rt_channel_info *channel_set,
 421                       u8 chanset_size, u8 chan) {
 422        int i;
 423
 424        for (i = 0; i < chanset_size; i++) {
 425                if (channel_set[i].ChannelNum == chan)
 426                        return 1;
 427        }
 428
 429        return 0;
 430}
 431
 432static void init_channel_list(struct rtw_adapter *padapter,
 433                              struct rt_channel_info *channel_set,
 434                              u8 chanset_size,
 435                              struct p2p_channels *channel_list)
 436{
 437        struct p2p_oper_class_map op_class[] = {
 438                { IEEE80211G,  81,   1,  13,  1, BW20 },
 439                { IEEE80211G,  82,  14,  14,  1, BW20 },
 440                { IEEE80211A, 115,  36,  48,  4, BW20 },
 441                { IEEE80211A, 116,  36,  44,  8, BW40PLUS },
 442                { IEEE80211A, 117,  40,  48,  8, BW40MINUS },
 443                { IEEE80211A, 124, 149, 161,  4, BW20 },
 444                { IEEE80211A, 125, 149, 169,  4, BW20 },
 445                { IEEE80211A, 126, 149, 157,  8, BW40PLUS },
 446                { IEEE80211A, 127, 153, 161,  8, BW40MINUS },
 447                { -1, 0, 0, 0, 0, BW20 }
 448        };
 449
 450        int cla, op;
 451
 452        cla = 0;
 453
 454        for (op = 0; op_class[op].op_class; op++) {
 455                u8 ch;
 456                struct p2p_oper_class_map *o = &op_class[op];
 457                struct p2p_reg_class *reg = NULL;
 458
 459                for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
 460                        if (!has_channel(channel_set, chanset_size, ch))
 461                                continue;
 462
 463                        if ((0 == padapter->registrypriv.ht_enable) &&
 464                            (o->inc == 8))
 465                                continue;
 466
 467                        if ((0 == (padapter->registrypriv.cbw40_enable & BIT(1))) &&
 468                                ((BW40MINUS == o->bw) || (BW40PLUS == o->bw)))
 469                                continue;
 470
 471                        if (reg == NULL) {
 472                                reg = &channel_list->reg_class[cla];
 473                                cla++;
 474                                reg->reg_class = o->op_class;
 475                                reg->channels = 0;
 476                        }
 477                        reg->channel[reg->channels] = ch;
 478                        reg->channels++;
 479                }
 480        }
 481        channel_list->reg_classes = cla;
 482}
 483
 484static u8 init_channel_set(struct rtw_adapter *padapter, u8 cplan,
 485                           struct rt_channel_info *c_set)
 486{
 487        u8 i, ch_size = 0;
 488        u8 b5GBand = false, b2_4GBand = false;
 489        u8 Index2G = 0, Index5G = 0;
 490
 491        memset(c_set, 0, sizeof(struct rt_channel_info) * MAX_CHANNEL_NUM);
 492
 493        if (cplan >= RT_CHANNEL_DOMAIN_MAX &&
 494            cplan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) {
 495                DBG_8723A("ChannelPlan ID %x error !!!!!\n", cplan);
 496                return ch_size;
 497        }
 498
 499        if (padapter->registrypriv.wireless_mode & WIRELESS_11G) {
 500                b2_4GBand = true;
 501                if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == cplan)
 502                        Index2G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index2G;
 503                else
 504                        Index2G = RTW_ChannelPlanMap[cplan].Index2G;
 505        }
 506
 507        if (padapter->registrypriv.wireless_mode & WIRELESS_11A) {
 508                b5GBand = true;
 509                if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == cplan)
 510                        Index5G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index5G;
 511                else
 512                        Index5G = RTW_ChannelPlanMap[cplan].Index5G;
 513        }
 514
 515        if (b2_4GBand) {
 516                for (i = 0; i < RTW_ChannelPlan2G[Index2G].Len; i++) {
 517                        c_set[ch_size].ChannelNum =
 518                                RTW_ChannelPlan2G[Index2G].Channel[i];
 519
 520                        if ((RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN == cplan) ||
 521                            /* Channel 1~11 is active, and 12~14 is passive */
 522                            RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G == cplan) {
 523                                if (c_set[ch_size].ChannelNum >= 1 &&
 524                                    c_set[ch_size].ChannelNum <= 11)
 525                                        c_set[ch_size].ScanType = SCAN_ACTIVE;
 526                                else if (c_set[ch_size].ChannelNum >= 12 &&
 527                                         c_set[ch_size].ChannelNum  <= 14)
 528                                        c_set[ch_size].ScanType = SCAN_PASSIVE;
 529                        } else if (RT_CHANNEL_DOMAIN_WORLD_WIDE_13 == cplan ||
 530                                   RT_CHANNEL_DOMAIN_WORLD_WIDE_5G == cplan ||
 531                                   RT_CHANNEL_DOMAIN_2G_WORLD == Index2G) {
 532                                /*  channel 12~13, passive scan */
 533                                if (c_set[ch_size].ChannelNum <= 11)
 534                                        c_set[ch_size].ScanType = SCAN_ACTIVE;
 535                                else
 536                                        c_set[ch_size].ScanType = SCAN_PASSIVE;
 537                        } else
 538                                c_set[ch_size].ScanType = SCAN_ACTIVE;
 539
 540                        ch_size++;
 541                }
 542        }
 543
 544        if (b5GBand) {
 545                for (i = 0; i < RTW_ChannelPlan5G[Index5G].Len; i++) {
 546                        if (RTW_ChannelPlan5G[Index5G].Channel[i] <= 48 ||
 547                            RTW_ChannelPlan5G[Index5G].Channel[i] >= 149) {
 548                                c_set[ch_size].ChannelNum =
 549                                        RTW_ChannelPlan5G[Index5G].Channel[i];
 550                                if (RT_CHANNEL_DOMAIN_WORLD_WIDE_5G == cplan) {
 551                                        /* passive scan for all 5G channels */
 552                                        c_set[ch_size].ScanType =
 553                                                SCAN_PASSIVE;
 554                                } else
 555                                        c_set[ch_size].ScanType =
 556                                                SCAN_ACTIVE;
 557                                DBG_8723A("%s(): channel_set[%d].ChannelNum = "
 558                                          "%d\n", __func__, ch_size,
 559                                          c_set[ch_size].ChannelNum);
 560                                ch_size++;
 561                        }
 562                }
 563        }
 564
 565        return ch_size;
 566}
 567
 568int init_mlme_ext_priv23a(struct rtw_adapter *padapter)
 569{
 570        struct registry_priv *pregistrypriv = &padapter->registrypriv;
 571        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
 572        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 573        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
 574
 575        pmlmeext->padapter = padapter;
 576
 577        init_mlme_ext_priv23a_value(padapter);
 578        pmlmeinfo->bAcceptAddbaReq = pregistrypriv->bAcceptAddbaReq;
 579
 580        init_mlme_ext_timer23a(padapter);
 581
 582#ifdef CONFIG_8723AU_AP_MODE
 583        init_mlme_ap_info23a(padapter);
 584#endif
 585
 586        pmlmeext->max_chan_nums = init_channel_set(padapter,
 587                                                   pmlmepriv->ChannelPlan,
 588                                                   pmlmeext->channel_set);
 589        init_channel_list(padapter, pmlmeext->channel_set,
 590                          pmlmeext->max_chan_nums, &pmlmeext->channel_list);
 591
 592        pmlmeext->chan_scan_time = SURVEY_TO;
 593        pmlmeext->mlmeext_init = true;
 594
 595        pmlmeext->active_keep_alive_check = true;
 596        return _SUCCESS;
 597}
 598
 599void free_mlme_ext_priv23a (struct mlme_ext_priv *pmlmeext)
 600{
 601        struct rtw_adapter *padapter = pmlmeext->padapter;
 602
 603        if (!padapter)
 604                return;
 605
 606        if (padapter->bDriverStopped == true) {
 607                del_timer_sync(&pmlmeext->survey_timer);
 608                del_timer_sync(&pmlmeext->link_timer);
 609                /* del_timer_sync(&pmlmeext->ADDBA_timer); */
 610        }
 611}
 612
 613static void
 614_mgt_dispatcher23a(struct rtw_adapter *padapter, struct mlme_handler *ptable,
 615                   struct recv_frame *precv_frame)
 616{
 617        struct sk_buff *skb = precv_frame->pkt;
 618        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 619
 620        if (ptable->func) {
 621                /* receive the frames that ra(a1) is my address
 622                   or ra(a1) is bc address. */
 623                if (!ether_addr_equal(hdr->addr1, myid(&padapter->eeprompriv))&&
 624                    !is_broadcast_ether_addr(hdr->addr1))
 625                        return;
 626
 627                ptable->func(padapter, precv_frame);
 628        }
 629}
 630
 631void mgt_dispatcher23a(struct rtw_adapter *padapter,
 632                    struct recv_frame *precv_frame)
 633{
 634        struct mlme_handler *ptable;
 635#ifdef CONFIG_8723AU_AP_MODE
 636        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 637#endif /* CONFIG_8723AU_AP_MODE */
 638        struct sk_buff *skb = precv_frame->pkt;
 639        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data;
 640        struct sta_info *psta;
 641        u16 stype;
 642        int index;
 643
 644        if (!ieee80211_is_mgmt(mgmt->frame_control))
 645                return;
 646
 647        /* receive the frames that ra(a1) is my address or ra(a1) is
 648           bc address. */
 649        if (!ether_addr_equal(mgmt->da, myid(&padapter->eeprompriv)) &&
 650            !is_broadcast_ether_addr(mgmt->da))
 651                return;
 652
 653        ptable = mlme_sta_tbl;
 654
 655        stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
 656        index = stype >> 4;
 657
 658        if (index > 13) {
 659                RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
 660                         "Currently we do not support reserved sub-fr-type =%d\n",
 661                         index);
 662                return;
 663        }
 664        ptable += index;
 665
 666        psta = rtw_get_stainfo23a(&padapter->stapriv, mgmt->sa);
 667
 668        if (psta) {
 669                if (ieee80211_has_retry(mgmt->frame_control)) {
 670                        if (precv_frame->attrib.seq_num ==
 671                            psta->RxMgmtFrameSeqNum) {
 672                                /* drop the duplicate management frame */
 673                                DBG_8723A("Drop duplicate management frame "
 674                                          "with seq_num = %d.\n",
 675                                          precv_frame->attrib.seq_num);
 676                                return;
 677                        }
 678                }
 679                psta->RxMgmtFrameSeqNum = precv_frame->attrib.seq_num;
 680        }
 681
 682#ifdef CONFIG_8723AU_AP_MODE
 683        switch (stype) {
 684        case IEEE80211_STYPE_AUTH:
 685                if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
 686                        ptable->func = &OnAuth23a;
 687                else
 688                        ptable->func = &OnAuth23aClient23a;
 689                /* pass through */
 690        case IEEE80211_STYPE_ASSOC_REQ:
 691        case IEEE80211_STYPE_REASSOC_REQ:
 692                _mgt_dispatcher23a(padapter, ptable, precv_frame);
 693                break;
 694        case IEEE80211_STYPE_PROBE_REQ:
 695                if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
 696                        _mgt_dispatcher23a(padapter, ptable, precv_frame);
 697                else
 698                        _mgt_dispatcher23a(padapter, ptable, precv_frame);
 699                break;
 700        case IEEE80211_STYPE_BEACON:
 701                _mgt_dispatcher23a(padapter, ptable, precv_frame);
 702                break;
 703        case IEEE80211_STYPE_ACTION:
 704                /* if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) */
 705                _mgt_dispatcher23a(padapter, ptable, precv_frame);
 706                break;
 707        default:
 708                _mgt_dispatcher23a(padapter, ptable, precv_frame);
 709                break;
 710        }
 711#else
 712        _mgt_dispatcher23a(padapter, ptable, precv_frame);
 713#endif
 714}
 715
 716/****************************************************************************
 717
 718Following are the callback functions for each subtype of the management frames
 719
 720*****************************************************************************/
 721
 722static int
 723OnProbeReq23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
 724{
 725        const u8 *ie;
 726        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 727        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
 728        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
 729        struct wlan_bssid_ex *cur = &pmlmeinfo->network;
 730        struct sk_buff *skb = precv_frame->pkt;
 731        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data;
 732        int len = skb->len;
 733
 734        if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
 735                return _SUCCESS;
 736
 737        if (!check_fwstate(pmlmepriv, _FW_LINKED) &&
 738            !check_fwstate(pmlmepriv,
 739                           WIFI_ADHOC_MASTER_STATE | WIFI_AP_STATE))
 740                return _SUCCESS;
 741
 742        if (unlikely(!ieee80211_is_probe_req(mgmt->frame_control))) {
 743                printk(KERN_WARNING "%s: Received non probe request frame\n",
 744                       __func__);
 745                return _FAIL;
 746        }
 747
 748        len -= offsetof(struct ieee80211_mgmt, u.probe_req.variable);
 749
 750        ie = cfg80211_find_ie(WLAN_EID_SSID, mgmt->u.probe_req.variable, len);
 751
 752        /* check (wildcard) SSID */
 753        if (!ie)
 754                goto out;
 755
 756        if ((ie[1] && memcmp(ie + 2, cur->Ssid.ssid, cur->Ssid.ssid_len)) ||
 757            (ie[1] == 0 && pmlmeinfo->hidden_ssid_mode)) {
 758                return _SUCCESS;
 759        }
 760
 761        if (check_fwstate(pmlmepriv, _FW_LINKED) &&
 762            pmlmepriv->cur_network.join_res)
 763                issue_probersp(padapter, mgmt->sa, false);
 764
 765out:
 766        return _SUCCESS;
 767}
 768
 769static int
 770OnProbeRsp23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
 771{
 772        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
 773
 774        if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
 775                report_survey_event23a(padapter, precv_frame);
 776                return _SUCCESS;
 777        }
 778
 779        return _SUCCESS;
 780}
 781
 782static int
 783OnBeacon23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
 784{
 785        int cam_idx;
 786        struct sta_info *psta;
 787        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
 788        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
 789        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 790        struct sta_priv *pstapriv = &padapter->stapriv;
 791        struct sk_buff *skb = precv_frame->pkt;
 792        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data;
 793        int pkt_len = skb->len;
 794        struct wlan_bssid_ex *pbss;
 795        int ret = _SUCCESS;
 796        u8 *p, *pie;
 797        int pie_len;
 798        u32 ielen = 0;
 799
 800        pie = mgmt->u.beacon.variable;
 801        pie_len = pkt_len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
 802        p = rtw_get_ie23a(pie, WLAN_EID_EXT_SUPP_RATES, &ielen, pie_len);
 803        if (p && ielen > 0) {
 804                if (p[1 + ielen] == 0x2D && p[2 + ielen] != 0x2D) {
 805                        /* Invalid value 0x2D is detected in Extended Supported
 806                         * Rates (ESR) IE. Try to fix the IE length to avoid
 807                         * failed Beacon parsing.
 808                         */
 809                        DBG_8723A("[WIFIDBG] Error in ESR IE is detected in "
 810                                  "Beacon of BSSID: %pM. Fix the length of "
 811                                  "ESR IE to avoid failed Beacon parsing.\n",
 812                                  mgmt->bssid);
 813                        p[1] = ielen - 1;
 814                }
 815        }
 816
 817        if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
 818                report_survey_event23a(padapter, precv_frame);
 819                return _SUCCESS;
 820        }
 821
 822        if (!ether_addr_equal(mgmt->bssid,
 823                              get_my_bssid23a(&pmlmeinfo->network)))
 824                goto out;
 825
 826        if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) {
 827                /* we should update current network before auth,
 828                   or some IE is wrong */
 829                pbss = collect_bss_info(padapter, precv_frame);
 830                if (pbss) {
 831                        update_network23a(&pmlmepriv->cur_network.network, pbss,
 832                                          padapter, true);
 833                        rtw_get_bcn_info23a(&pmlmepriv->cur_network);
 834                        kfree(pbss);
 835                }
 836
 837                /* check the vendor of the assoc AP */
 838                pmlmeinfo->assoc_AP_vendor =
 839                        check_assoc_AP23a((u8 *)&mgmt->u.beacon, pkt_len -
 840                                          offsetof(struct ieee80211_mgmt, u));
 841
 842                /* update TSF Value */
 843                rtw_update_TSF(pmlmeext, mgmt);
 844
 845                /* start auth */
 846                start_clnt_auth(padapter);
 847
 848                return _SUCCESS;
 849        }
 850
 851        if (((pmlmeinfo->state & 0x03) == MSR_AP) &&
 852            (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) {
 853                psta = rtw_get_stainfo23a(pstapriv, mgmt->sa);
 854                if (psta) {
 855                        ret = rtw_check_bcn_info23a(padapter, mgmt, pkt_len);
 856                        if (ret != _SUCCESS) {
 857                                DBG_8723A_LEVEL(_drv_always_, "ap has changed, "
 858                                                "disconnect now\n");
 859                                receive_disconnect23a(padapter, pmlmeinfo->network.MacAddress, 65535);
 860                                return _SUCCESS;
 861                        }
 862                        /* update WMM, ERP in the beacon */
 863                        /* todo: the timer is used instead of
 864                           the number of the beacon received */
 865                        if ((sta_rx_pkts(psta) & 0xf) == 0) {
 866                                /* DBG_8723A("update_bcn_info\n"); */
 867                                update_beacon23a_info(padapter, mgmt,
 868                                                      pkt_len, psta);
 869                        }
 870                }
 871        } else if ((pmlmeinfo->state&0x03) == MSR_ADHOC) {
 872                psta = rtw_get_stainfo23a(pstapriv, mgmt->sa);
 873                if (psta) {
 874                        /* update WMM, ERP in the beacon */
 875                        /* todo: the timer is used instead of the
 876                           number of the beacon received */
 877                        if ((sta_rx_pkts(psta) & 0xf) == 0) {
 878                                /* DBG_8723A("update_bcn_info\n"); */
 879                                update_beacon23a_info(padapter, mgmt,
 880                                                      pkt_len, psta);
 881                        }
 882                } else {
 883                        /* allocate a new CAM entry for IBSS station */
 884                        cam_idx = allocate_fw_sta_entry23a(padapter);
 885                        if (cam_idx == NUM_STA)
 886                                goto out;
 887
 888                        /* get supported rate */
 889                        if (update_sta_support_rate23a(padapter, pie, pie_len,
 890                                                       cam_idx) == _FAIL) {
 891                                pmlmeinfo->FW_sta_info[cam_idx].status = 0;
 892                                goto out;
 893                        }
 894
 895                        /* update TSF Value */
 896                        rtw_update_TSF(pmlmeext, mgmt);
 897
 898                        /* report sta add event */
 899                        report_add_sta_event23a(padapter, mgmt->sa,
 900                                                cam_idx);
 901                }
 902        }
 903
 904out:
 905
 906        return _SUCCESS;
 907}
 908
 909#ifdef CONFIG_8723AU_AP_MODE
 910static int
 911OnAuth23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
 912{
 913        static struct sta_info stat;
 914        struct sta_info *pstat = NULL;
 915        struct sta_priv *pstapriv = &padapter->stapriv;
 916        struct security_priv *psecuritypriv = &padapter->securitypriv;
 917        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
 918        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
 919        struct sk_buff *skb = precv_frame->pkt;
 920        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data;
 921        u8 *pframe;
 922        const u8 *p;
 923        unsigned char *sa;
 924        u16 auth_mode, seq, algorithm;
 925        int status, len = skb->len;
 926
 927        if ((pmlmeinfo->state & 0x03) != MSR_AP)
 928                return _FAIL;
 929
 930        DBG_8723A("+OnAuth23a\n");
 931
 932        sa = mgmt->sa;
 933
 934        auth_mode = psecuritypriv->dot11AuthAlgrthm;
 935
 936        pframe = mgmt->u.auth.variable;
 937        len = skb->len - offsetof(struct ieee80211_mgmt, u.auth.variable);
 938
 939        seq = le16_to_cpu(mgmt->u.auth.auth_transaction);
 940        algorithm = le16_to_cpu(mgmt->u.auth.auth_alg);
 941
 942        DBG_8723A("auth alg =%x, seq =%X\n", algorithm, seq);
 943
 944        if (auth_mode == 2 &&
 945            psecuritypriv->dot11PrivacyAlgrthm != WLAN_CIPHER_SUITE_WEP40 &&
 946            psecuritypriv->dot11PrivacyAlgrthm != WLAN_CIPHER_SUITE_WEP104)
 947                auth_mode = 0;
 948
 949        /*  rx a shared-key auth but shared not enabled, or */
 950        /*  rx a open-system auth but shared-key is enabled */
 951        if ((algorithm != WLAN_AUTH_OPEN && auth_mode == 0) ||
 952            (algorithm == WLAN_AUTH_OPEN && auth_mode == 1)) {
 953                DBG_8723A("auth rejected due to bad alg [alg =%d, auth_mib "
 954                          "=%d] %02X%02X%02X%02X%02X%02X\n",
 955                          algorithm, auth_mode,
 956                          sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]);
 957
 958                status = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
 959
 960                goto auth_fail;
 961        }
 962
 963        if (rtw_access_ctrl23a(padapter, sa) == false) {
 964                status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
 965                goto auth_fail;
 966        }
 967
 968        pstat = rtw_get_stainfo23a(pstapriv, sa);
 969        if (!pstat) {
 970                /*  allocate a new one */
 971                DBG_8723A("going to alloc stainfo for sa =%pM\n", sa);
 972                pstat = rtw_alloc_stainfo23a(pstapriv, sa, GFP_ATOMIC);
 973                if (!pstat) {
 974                        DBG_8723A(" Exceed the upper limit of supported "
 975                                  "clients...\n");
 976                        status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
 977                        goto auth_fail;
 978                }
 979
 980                pstat->state = WIFI_FW_AUTH_NULL;
 981                pstat->auth_seq = 0;
 982
 983                /* pstat->flags = 0; */
 984                /* pstat->capability = 0; */
 985        } else {
 986                spin_lock_bh(&pstapriv->asoc_list_lock);
 987                if (!list_empty(&pstat->asoc_list)) {
 988                        list_del_init(&pstat->asoc_list);
 989                        pstapriv->asoc_list_cnt--;
 990                        if (pstat->expire_to > 0) {
 991                                /* TODO: STA re_auth within expire_to */
 992                        }
 993                }
 994                spin_unlock_bh(&pstapriv->asoc_list_lock);
 995
 996                if (seq == 1) {
 997                        /* TODO: STA re_auth and auth timeout */
 998                }
 999        }
1000
1001        spin_lock_bh(&pstapriv->auth_list_lock);
1002        if (list_empty(&pstat->auth_list)) {
1003                list_add_tail(&pstat->auth_list, &pstapriv->auth_list);
1004                pstapriv->auth_list_cnt++;
1005        }
1006        spin_unlock_bh(&pstapriv->auth_list_lock);
1007
1008        if (pstat->auth_seq == 0)
1009                pstat->expire_to = pstapriv->auth_to;
1010
1011        if ((pstat->auth_seq + 1) != seq) {
1012                DBG_8723A("(1)auth rejected because out of seq [rx_seq =%d, "
1013                          "exp_seq =%d]!\n", seq, pstat->auth_seq+1);
1014                status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
1015                goto auth_fail;
1016        }
1017
1018        if (algorithm == WLAN_AUTH_OPEN && (auth_mode == 0 || auth_mode == 2)) {
1019                if (seq == 1) {
1020                        pstat->state &= ~WIFI_FW_AUTH_NULL;
1021                        pstat->state |= WIFI_FW_AUTH_SUCCESS;
1022                        pstat->expire_to = pstapriv->assoc_to;
1023                        pstat->authalg = algorithm;
1024                } else {
1025                        DBG_8723A("(2)auth rejected because out of seq "
1026                                  "[rx_seq =%d, exp_seq =%d]!\n",
1027                                  seq, pstat->auth_seq+1);
1028                        status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
1029                        goto auth_fail;
1030                }
1031        } else { /*  shared system or auto authentication */
1032                if (seq == 1) {
1033                        /* prepare for the challenging txt... */
1034                        pstat->state &= ~WIFI_FW_AUTH_NULL;
1035                        pstat->state |= WIFI_FW_AUTH_STATE;
1036                        pstat->authalg = algorithm;
1037                        pstat->auth_seq = 2;
1038                } else if (seq == 3) {
1039                        /* checking for challenging txt... */
1040                        DBG_8723A("checking for challenging txt...\n");
1041
1042                        p = cfg80211_find_ie(WLAN_EID_CHALLENGE, pframe, len);
1043                        if (!p || p[1] <= 0) {
1044                                DBG_8723A("auth rejected because challenge "
1045                                          "failure!(1)\n");
1046                                status = WLAN_STATUS_CHALLENGE_FAIL;
1047                                goto auth_fail;
1048                        }
1049
1050                        if (!memcmp(p + 2, pstat->chg_txt, 128)) {
1051                                pstat->state &= ~WIFI_FW_AUTH_STATE;
1052                                pstat->state |= WIFI_FW_AUTH_SUCCESS;
1053                                /*  challenging txt is correct... */
1054                                pstat->expire_to =  pstapriv->assoc_to;
1055                        } else {
1056                                DBG_8723A("auth rejected because challenge "
1057                                          "failure!\n");
1058                                status = WLAN_STATUS_CHALLENGE_FAIL;
1059                                goto auth_fail;
1060                        }
1061                } else {
1062                        DBG_8723A("(3)auth rejected because out of seq "
1063                                  "[rx_seq =%d, exp_seq =%d]!\n",
1064                                  seq, pstat->auth_seq+1);
1065                        status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
1066                        goto auth_fail;
1067                }
1068        }
1069
1070        /*  Now, we are going to issue_auth... */
1071        pstat->auth_seq = seq + 1;
1072
1073        issue_auth(padapter, pstat, WLAN_STATUS_SUCCESS);
1074
1075        if (pstat->state & WIFI_FW_AUTH_SUCCESS)
1076                pstat->auth_seq = 0;
1077
1078        return _SUCCESS;
1079
1080auth_fail:
1081
1082        if (pstat)
1083                rtw_free_stainfo23a(padapter, pstat);
1084
1085        pstat = &stat;
1086        memset((char *)pstat, '\0', sizeof(stat));
1087        pstat->auth_seq = 2;
1088        ether_addr_copy(pstat->hwaddr, sa);
1089
1090        issue_auth(padapter, pstat, (unsigned short)status);
1091
1092        return _FAIL;
1093}
1094#endif
1095
1096static int
1097OnAuth23aClient23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
1098{
1099        unsigned int seq, status, algthm;
1100        unsigned int go2asoc = 0;
1101        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
1102        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
1103        struct sk_buff *skb = precv_frame->pkt;
1104        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data;
1105        const u8 *p;
1106        u8 *pie;
1107        int plen = skb->len;
1108
1109        DBG_8723A("%s\n", __func__);
1110
1111        /* check A1 matches or not */
1112        if (!ether_addr_equal(myid(&padapter->eeprompriv), mgmt->da))
1113                return _SUCCESS;
1114
1115        if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE))
1116                return _SUCCESS;
1117
1118        pie = mgmt->u.auth.variable;
1119        plen -= offsetof(struct ieee80211_mgmt, u.auth.variable);
1120
1121        algthm = le16_to_cpu(mgmt->u.auth.auth_alg);
1122        seq = le16_to_cpu(mgmt->u.auth.auth_transaction);
1123        status = le16_to_cpu(mgmt->u.auth.status_code);
1124
1125        if (status) {
1126                DBG_8723A("clnt auth fail, status: %d\n", status);
1127                /*  pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) */
1128                if (status == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
1129                        if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared)
1130                                pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open;
1131                        else
1132                                pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared;
1133                        /* pmlmeinfo->reauth_count = 0; */
1134                }
1135
1136                set_link_timer(pmlmeext, 1);
1137                goto authclnt_fail;
1138        }
1139
1140        if (seq == 2) {
1141                if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) {
1142                        /*  legendary shared system */
1143                        p = cfg80211_find_ie(WLAN_EID_CHALLENGE, pie, plen);
1144
1145                        if (!p) {
1146                                /* DBG_8723A("marc: no challenge text?\n"); */
1147                                goto authclnt_fail;
1148                        }
1149
1150                        memcpy((void *)(pmlmeinfo->chg_txt), p + 2, p[1]);
1151                        pmlmeinfo->auth_seq = 3;
1152                        issue_auth(padapter, NULL, 0);
1153                        set_link_timer(pmlmeext, REAUTH_TO);
1154
1155                        return _SUCCESS;
1156                } else {
1157                        /*  open system */
1158                        go2asoc = 1;
1159                }
1160        } else if (seq == 4) {
1161                if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared)
1162                        go2asoc = 1;
1163                else
1164                        goto authclnt_fail;
1165        } else {
1166                /*  this is also illegal */
1167                /* DBG_8723A("marc: clnt auth failed due to illegal seq =%x\n",
1168                   seq); */
1169                goto authclnt_fail;
1170        }
1171
1172        if (go2asoc) {
1173                DBG_8723A_LEVEL(_drv_always_, "auth success, start assoc\n");
1174                start_clnt_assoc(padapter);
1175                return _SUCCESS;
1176        }
1177
1178authclnt_fail:
1179
1180        /* pmlmeinfo->state &= ~(WIFI_FW_AUTH_STATE); */
1181
1182        return _FAIL;
1183}
1184
1185#ifdef CONFIG_8723AU_AP_MODE
1186static int rtw_validate_vendor_specific_ies(const u8 *pos, int elen)
1187{
1188        unsigned int oui;
1189
1190        /* first 3 bytes in vendor specific information element are the IEEE
1191         * OUI of the vendor. The following byte is used a vendor specific
1192         * sub-type. */
1193        if (elen < 4) {
1194                DBG_8723A("short vendor specific information element "
1195                          "ignored (len =%i)\n", elen);
1196                return -EINVAL;
1197        }
1198
1199        oui = RTW_GET_BE24(pos);
1200        switch (oui) {
1201        case WLAN_OUI_MICROSOFT:
1202                /* Microsoft/Wi-Fi information elements are further typed and
1203                 * subtyped */
1204                switch (pos[3]) {
1205                case WLAN_OUI_TYPE_MICROSOFT_WPA:
1206                        /* Microsoft OUI (00:50:F2) with OUI Type 1:
1207                         * real WPA information element */
1208                        break;
1209                case WLAN_OUI_TYPE_MICROSOFT_WMM:
1210                        if (elen < 5) {
1211                                DBG_8723A("short WME information element "
1212                                          "ignored (len =%i)\n", elen);
1213                                return -EINVAL;
1214                        }
1215                        switch (pos[4]) {
1216                        case WME_OUI_SUBTYPE_INFORMATION_ELEMENT:
1217                        case WME_OUI_SUBTYPE_PARAMETER_ELEMENT:
1218                                break;
1219                        case WME_OUI_SUBTYPE_TSPEC_ELEMENT:
1220                                break;
1221                        default:
1222                                DBG_8723A("unknown WME information element "
1223                                          "ignored (subtype =%d len =%i)\n",
1224                                           pos[4], elen);
1225                                return -EINVAL;
1226                        }
1227                        break;
1228                case WLAN_OUI_TYPE_MICROSOFT_WPS:
1229                        /* Wi-Fi Protected Setup (WPS) IE */
1230                        break;
1231                default:
1232                        DBG_8723A("Unknown Microsoft information element "
1233                                  "ignored (type =%d len =%i)\n",
1234                                  pos[3], elen);
1235                        return -EINVAL;
1236                }
1237                break;
1238
1239        case OUI_BROADCOM:
1240                switch (pos[3]) {
1241                case VENDOR_HT_CAPAB_OUI_TYPE:
1242                        break;
1243                default:
1244                        DBG_8723A("Unknown Broadcom information element "
1245                                  "ignored (type =%d len =%i)\n", pos[3], elen);
1246                        return -EINVAL;
1247                }
1248                break;
1249
1250        default:
1251                DBG_8723A("unknown vendor specific information element "
1252                          "ignored (vendor OUI %02x:%02x:%02x len =%i)\n",
1253                           pos[0], pos[1], pos[2], elen);
1254                return -EINVAL;
1255        }
1256
1257        return 0;
1258}
1259
1260static int rtw_validate_frame_ies(const u8 *start, uint len)
1261{
1262        const u8 *pos = start;
1263        int left = len;
1264        int unknown = 0;
1265
1266        while (left >= 2) {
1267                u8 id, elen;
1268
1269                id = *pos++;
1270                elen = *pos++;
1271                left -= 2;
1272
1273                if (elen > left) {
1274                        DBG_8723A("%s: IEEE 802.11 failed (id =%d elen =%d "
1275                                  "left =%i)\n", __func__, id, elen, left);
1276                        return -EINVAL;
1277                }
1278
1279                switch (id) {
1280                case WLAN_EID_SSID:
1281                case WLAN_EID_SUPP_RATES:
1282                case WLAN_EID_FH_PARAMS:
1283                case WLAN_EID_DS_PARAMS:
1284                case WLAN_EID_CF_PARAMS:
1285                case WLAN_EID_TIM:
1286                case WLAN_EID_IBSS_PARAMS:
1287                case WLAN_EID_CHALLENGE:
1288                case WLAN_EID_ERP_INFO:
1289                case WLAN_EID_EXT_SUPP_RATES:
1290                        break;
1291                case WLAN_EID_VENDOR_SPECIFIC:
1292                        if (rtw_validate_vendor_specific_ies(pos, elen))
1293                                unknown++;
1294                        break;
1295                case WLAN_EID_RSN:
1296                case WLAN_EID_PWR_CAPABILITY:
1297                case WLAN_EID_SUPPORTED_CHANNELS:
1298                case WLAN_EID_MOBILITY_DOMAIN:
1299                case WLAN_EID_FAST_BSS_TRANSITION:
1300                case WLAN_EID_TIMEOUT_INTERVAL:
1301                case WLAN_EID_HT_CAPABILITY:
1302                case WLAN_EID_HT_OPERATION:
1303                default:
1304                        unknown++;
1305                        DBG_8723A("%s IEEE 802.11 ignored unknown element "
1306                                  "(id =%d elen =%d)\n", __func__, id, elen);
1307                        break;
1308                }
1309
1310                left -= elen;
1311                pos += elen;
1312        }
1313
1314        if (left)
1315                return -EINVAL;
1316
1317        return 0;
1318}
1319#endif
1320
1321static int
1322OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
1323{
1324#ifdef CONFIG_8723AU_AP_MODE
1325        u16 capab_info, listen_interval;
1326        struct sta_info *pstat;
1327        unsigned char reassoc;
1328        int i, wpa_ie_len, left;
1329        unsigned char supportRate[16];
1330        int supportRateNum;
1331        unsigned short status = WLAN_STATUS_SUCCESS;
1332        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1333        struct security_priv *psecuritypriv = &padapter->securitypriv;
1334        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
1335        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
1336        struct wlan_bssid_ex *cur = &pmlmeinfo->network;
1337        struct sta_priv *pstapriv = &padapter->stapriv;
1338        struct sk_buff *skb = precv_frame->pkt;
1339        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data;
1340        const u8 *pos, *p, *wpa_ie, *wps_ie;
1341        u8 *pframe = skb->data;
1342        uint pkt_len = skb->len;
1343        int r;
1344
1345        if ((pmlmeinfo->state & 0x03) != MSR_AP)
1346                return _FAIL;
1347
1348        left = pkt_len - sizeof(struct ieee80211_hdr_3addr);
1349        if (ieee80211_is_assoc_req(mgmt->frame_control)) {
1350                reassoc = 0;
1351                pos = mgmt->u.assoc_req.variable;
1352                left -= offsetof(struct ieee80211_mgmt, u.assoc_req.variable);
1353        } else { /*  WIFI_REASSOCREQ */
1354                reassoc = 1;
1355                pos = mgmt->u.reassoc_req.variable;
1356                left -= offsetof(struct ieee80211_mgmt, u.reassoc_req.variable);
1357        }
1358
1359        if (left < 0) {
1360                DBG_8723A("handle_assoc(reassoc =%d) - too short payload "
1361                          "(len =%lu)\n", reassoc, (unsigned long)pkt_len);
1362                return _FAIL;
1363        }
1364
1365        pstat = rtw_get_stainfo23a(pstapriv, mgmt->sa);
1366        if (!pstat) {
1367                status = WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA;
1368                goto asoc_class2_error;
1369        }
1370
1371        /* These two are located at the same offsets whether it's an
1372         * assoc_req or a reassoc_req */
1373        capab_info = get_unaligned_le16(&mgmt->u.assoc_req.capab_info);
1374        listen_interval =
1375                get_unaligned_le16(&mgmt->u.assoc_req.listen_interval);
1376
1377        DBG_8723A("%s\n", __func__);
1378
1379        /*  check if this stat has been successfully authenticated/assocated */
1380        if (!(pstat->state & WIFI_FW_AUTH_SUCCESS)) {
1381                if (!(pstat->state & WIFI_FW_ASSOC_SUCCESS)) {
1382                        status = WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA;
1383                        goto asoc_class2_error;
1384                } else {
1385                        pstat->state &= (~WIFI_FW_ASSOC_SUCCESS);
1386                        pstat->state |= WIFI_FW_ASSOC_STATE;
1387                }
1388        } else {
1389                pstat->state &= (~WIFI_FW_AUTH_SUCCESS);
1390                pstat->state |= WIFI_FW_ASSOC_STATE;
1391        }
1392
1393        pstat->capability = capab_info;
1394
1395        /* now parse all ieee802_11 ie to point to elems */
1396
1397        if (rtw_validate_frame_ies(pos, left)) {
1398                DBG_8723A("STA %pM sent invalid association request\n",
1399                          pstat->hwaddr);
1400                status = WLAN_STATUS_UNSPECIFIED_FAILURE;
1401                goto OnAssocReq23aFail;
1402        }
1403
1404        /*  now we should check all the fields... */
1405        /*  checking SSID */
1406        p = cfg80211_find_ie(WLAN_EID_SSID, pos, left);
1407        if (!p || p[1] == 0) {
1408                /*  broadcast ssid, however it is not allowed in assocreq */
1409                DBG_8723A("STA %pM sent invalid association request lacking an SSID\n",
1410                          pstat->hwaddr);
1411                status = WLAN_STATUS_UNSPECIFIED_FAILURE;
1412                goto OnAssocReq23aFail;
1413        } else {
1414                /*  check if ssid match */
1415                if (memcmp(p + 2, cur->Ssid.ssid, cur->Ssid.ssid_len))
1416                        status = WLAN_STATUS_UNSPECIFIED_FAILURE;
1417
1418                if (p[1] != cur->Ssid.ssid_len)
1419                        status = WLAN_STATUS_UNSPECIFIED_FAILURE;
1420        }
1421
1422        if (status != WLAN_STATUS_SUCCESS)
1423                goto OnAssocReq23aFail;
1424
1425        /*  check if the supported rate is ok */
1426        p = cfg80211_find_ie(WLAN_EID_SUPP_RATES, pos, left);
1427        if (!p) {
1428                DBG_8723A("Rx a sta assoc-req which supported rate is "
1429                          "empty!\n");
1430                /*  use our own rate set as statoin used */
1431                /* memcpy(supportRate, AP_BSSRATE, AP_BSSRATE_LEN); */
1432                /* supportRateNum = AP_BSSRATE_LEN; */
1433
1434                status = WLAN_STATUS_UNSPECIFIED_FAILURE;
1435                goto OnAssocReq23aFail;
1436        } else {
1437                memcpy(supportRate, p + 2, p[1]);
1438                supportRateNum = p[1];
1439
1440                p = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, pos, left);
1441                if (p) {
1442                        if (supportRateNum <= sizeof(supportRate)) {
1443                                memcpy(supportRate+supportRateNum, p + 2, p[1]);
1444                                supportRateNum += p[1];
1445                        }
1446                }
1447        }
1448
1449        /* todo: mask supportRate between AP & STA -> move to update raid */
1450        /* get_matched_rate(pmlmeext, supportRate, &supportRateNum, 0); */
1451
1452        /* update station supportRate */
1453        pstat->bssratelen = supportRateNum;
1454        memcpy(pstat->bssrateset, supportRate, supportRateNum);
1455        Update23aTblForSoftAP(pstat->bssrateset, pstat->bssratelen);
1456
1457        /* check RSN/WPA/WPS */
1458        pstat->dot8021xalg = 0;
1459        pstat->wpa_psk = 0;
1460        pstat->wpa_group_cipher = 0;
1461        pstat->wpa2_group_cipher = 0;
1462        pstat->wpa_pairwise_cipher = 0;
1463        pstat->wpa2_pairwise_cipher = 0;
1464        memset(pstat->wpa_ie, 0, sizeof(pstat->wpa_ie));
1465
1466        wpa_ie = cfg80211_find_ie(WLAN_EID_RSN, pos, left);
1467        if (!wpa_ie)
1468                wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
1469                                                 WLAN_OUI_TYPE_MICROSOFT_WPA,
1470                                                 pos, left);
1471        if (wpa_ie) {
1472                int group_cipher = 0, pairwise_cipher = 0;
1473
1474                wpa_ie_len = wpa_ie[1];
1475                if (psecuritypriv->wpa_psk & BIT(1)) {
1476                        r = rtw_parse_wpa2_ie23a(wpa_ie, wpa_ie_len + 2,
1477                                                 &group_cipher,
1478                                                 &pairwise_cipher, NULL);
1479                        if (r == _SUCCESS) {
1480                                pstat->dot8021xalg = 1;/* psk,  todo:802.1x */
1481                                pstat->wpa_psk |= BIT(1);
1482
1483                                pstat->wpa2_group_cipher = group_cipher &
1484                                        psecuritypriv->wpa2_group_cipher;
1485                                pstat->wpa2_pairwise_cipher = pairwise_cipher &
1486                                        psecuritypriv->wpa2_pairwise_cipher;
1487                        } else
1488                                status = WLAN_STATUS_INVALID_IE;
1489                } else if (psecuritypriv->wpa_psk & BIT(0)) {
1490                        r = rtw_parse_wpa_ie23a(wpa_ie, wpa_ie_len + 2,
1491                                                &group_cipher, &pairwise_cipher,
1492                                                NULL);
1493                        if (r == _SUCCESS) {
1494                                pstat->dot8021xalg = 1;/* psk,  todo:802.1x */
1495                                pstat->wpa_psk |= BIT(0);
1496
1497                                pstat->wpa_group_cipher = group_cipher &
1498                                        psecuritypriv->wpa_group_cipher;
1499                                pstat->wpa_pairwise_cipher = pairwise_cipher &
1500                                        psecuritypriv->wpa_pairwise_cipher;
1501                        } else
1502                                status = WLAN_STATUS_INVALID_IE;
1503                } else {
1504                        wpa_ie = NULL;
1505                        wpa_ie_len = 0;
1506                }
1507                if (wpa_ie && status == WLAN_STATUS_SUCCESS) {
1508                        if (!pstat->wpa_group_cipher)
1509                                status = WLAN_STATUS_INVALID_GROUP_CIPHER;
1510
1511                        if (!pstat->wpa_pairwise_cipher)
1512                                status = WLAN_STATUS_INVALID_PAIRWISE_CIPHER;
1513                }
1514        }
1515
1516        if (status != WLAN_STATUS_SUCCESS)
1517                goto OnAssocReq23aFail;
1518
1519        pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
1520
1521        wps_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
1522                                         WLAN_OUI_TYPE_MICROSOFT_WPS,
1523                                         pos, left);
1524
1525        if (!wpa_ie) {
1526                if (wps_ie) {
1527                        DBG_8723A("STA included WPS IE in (Re)Association "
1528                                  "Request - assume WPS is used\n");
1529                        pstat->flags |= WLAN_STA_WPS;
1530                } else {
1531                        DBG_8723A("STA did not include WPA/RSN IE in (Re)"
1532                                   "Association Request - possible WPS use\n");
1533                        pstat->flags |= WLAN_STA_MAYBE_WPS;
1534                }
1535        } else {
1536                int copy_len;
1537
1538                if (psecuritypriv->wpa_psk == 0) {
1539                        DBG_8723A("STA %pM: WPA/RSN IE in association request, but AP don't support WPA/RSN\n",
1540                                  pstat->hwaddr);
1541
1542                        status = WLAN_STATUS_INVALID_IE;
1543
1544                        goto OnAssocReq23aFail;
1545                }
1546
1547                if (wps_ie) {
1548                        DBG_8723A("STA included WPS IE in (Re)Association "
1549                                  "Request - WPS is used\n");
1550                        pstat->flags |= WLAN_STA_WPS;
1551                        copy_len = 0;
1552                } else {
1553                        copy_len = ((wpa_ie_len + 2) > sizeof(pstat->wpa_ie)) ?
1554                                sizeof(pstat->wpa_ie) : (wpa_ie_len + 2);
1555                }
1556
1557                if (copy_len > 0)
1558                        memcpy(pstat->wpa_ie, wpa_ie - 2, copy_len);
1559        }
1560
1561        /*  check if there is WMM IE & support WWM-PS */
1562        pstat->flags &= ~WLAN_STA_WME;
1563        pstat->qos_option = 0;
1564        pstat->qos_info = 0;
1565        pstat->has_legacy_ac = true;
1566        pstat->uapsd_vo = 0;
1567        pstat->uapsd_vi = 0;
1568        pstat->uapsd_be = 0;
1569        pstat->uapsd_bk = 0;
1570        if (pmlmepriv->qos_option) {
1571                const u8 *end = pos + left;
1572
1573                p = pos;
1574
1575                for (;;) {
1576                        left = end - p;
1577                        p = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
1578                                                    WLAN_OUI_TYPE_MICROSOFT_WMM,
1579                                                    p, left);
1580                        if (p) {
1581                                pstat->flags |= WLAN_STA_WME;
1582
1583                                pstat->qos_option = 1;
1584                                pstat->qos_info = *(p + 8);
1585
1586                                pstat->max_sp_len =
1587                                        (pstat->qos_info >> 5) & 0x3;
1588
1589                                if ((pstat->qos_info & 0xf) != 0xf)
1590                                        pstat->has_legacy_ac = true;
1591                                else
1592                                        pstat->has_legacy_ac = false;
1593
1594                                if (pstat->qos_info & 0xf) {
1595                                        if (pstat->qos_info & BIT(0))
1596                                                pstat->uapsd_vo = BIT(0)|BIT(1);
1597                                        else
1598                                                pstat->uapsd_vo = 0;
1599
1600                                        if (pstat->qos_info & BIT(1))
1601                                                pstat->uapsd_vi = BIT(0)|BIT(1);
1602                                        else
1603                                                pstat->uapsd_vi = 0;
1604
1605                                        if (pstat->qos_info & BIT(2))
1606                                                pstat->uapsd_bk = BIT(0)|BIT(1);
1607                                        else
1608                                                pstat->uapsd_bk = 0;
1609
1610                                        if (pstat->qos_info & BIT(3))
1611                                                pstat->uapsd_be = BIT(0)|BIT(1);
1612                                        else
1613                                                pstat->uapsd_be = 0;
1614
1615                                        break;
1616                                }
1617                        } else {
1618                                break;
1619                        }
1620                        p = p + p[1] + 2;
1621                }
1622        }
1623
1624        /* save HT capabilities in the sta object */
1625        memset(&pstat->htpriv.ht_cap, 0, sizeof(struct ieee80211_ht_cap));
1626        p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, pos, left);
1627
1628        if (p && p[1] >= sizeof(struct ieee80211_ht_cap)) {
1629                pstat->flags |= WLAN_STA_HT;
1630
1631                pstat->flags |= WLAN_STA_WME;
1632
1633                memcpy(&pstat->htpriv.ht_cap, p + 2,
1634                       sizeof(struct ieee80211_ht_cap));
1635        } else
1636                pstat->flags &= ~WLAN_STA_HT;
1637
1638        if (!pmlmepriv->htpriv.ht_option && pstat->flags & WLAN_STA_HT){
1639                status = WLAN_STATUS_UNSPECIFIED_FAILURE;
1640                goto OnAssocReq23aFail;
1641        }
1642
1643        if (pstat->flags & WLAN_STA_HT &&
1644            (pstat->wpa2_pairwise_cipher & WPA_CIPHER_TKIP ||
1645             pstat->wpa_pairwise_cipher & WPA_CIPHER_TKIP)) {
1646                DBG_8723A("HT: %pM tried to use TKIP with HT association\n",
1647                          pstat->hwaddr);
1648
1649                /* status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; */
1650                /* goto OnAssocReq23aFail; */
1651        }
1652
1653        pstat->flags |= WLAN_STA_NONERP;
1654        for (i = 0; i < pstat->bssratelen; i++) {
1655                if ((pstat->bssrateset[i] & 0x7f) > 22) {
1656                        pstat->flags &= ~WLAN_STA_NONERP;
1657                        break;
1658                }
1659        }
1660
1661        if (pstat->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
1662                pstat->flags |= WLAN_STA_SHORT_PREAMBLE;
1663        else
1664                pstat->flags &= ~WLAN_STA_SHORT_PREAMBLE;
1665
1666        if (status != WLAN_STATUS_SUCCESS)
1667                goto OnAssocReq23aFail;
1668
1669        /* TODO: identify_proprietary_vendor_ie(); */
1670        /*  Realtek proprietary IE */
1671        /*  identify if this is Broadcom sta */
1672        /*  identify if this is ralink sta */
1673        /*  Customer proprietary IE */
1674
1675        /* get a unique AID */
1676        if (pstat->aid > 0) {
1677                DBG_8723A("  old AID %d\n", pstat->aid);
1678        } else {
1679                for (pstat->aid = 1; pstat->aid <= NUM_STA; pstat->aid++)
1680                        if (pstapriv->sta_aid[pstat->aid - 1] == NULL)
1681                                break;
1682
1683                if (pstat->aid > NUM_STA)
1684                        pstat->aid = NUM_STA;
1685                if (pstat->aid > pstapriv->max_num_sta) {
1686
1687                        pstat->aid = 0;
1688
1689                        DBG_8723A("  no room for more AIDs\n");
1690
1691                        status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
1692
1693                        goto OnAssocReq23aFail;
1694                } else {
1695                        pstapriv->sta_aid[pstat->aid - 1] = pstat;
1696                        DBG_8723A("allocate new AID = (%d)\n", pstat->aid);
1697                }
1698        }
1699
1700        pstat->state &= ~WIFI_FW_ASSOC_STATE;
1701        pstat->state |= WIFI_FW_ASSOC_SUCCESS;
1702
1703        spin_lock_bh(&pstapriv->auth_list_lock);
1704        if (!list_empty(&pstat->auth_list)) {
1705                list_del_init(&pstat->auth_list);
1706                pstapriv->auth_list_cnt--;
1707        }
1708        spin_unlock_bh(&pstapriv->auth_list_lock);
1709
1710        spin_lock_bh(&pstapriv->asoc_list_lock);
1711        if (list_empty(&pstat->asoc_list)) {
1712                pstat->expire_to = pstapriv->expire_to;
1713                list_add_tail(&pstat->asoc_list, &pstapriv->asoc_list);
1714                pstapriv->asoc_list_cnt++;
1715        }
1716        spin_unlock_bh(&pstapriv->asoc_list_lock);
1717
1718        /*  now the station is qualified to join our BSS... */
1719        if (pstat && pstat->state & WIFI_FW_ASSOC_SUCCESS &&
1720            status == WLAN_STATUS_SUCCESS) {
1721#ifdef CONFIG_8723AU_AP_MODE
1722                /* 1 bss_cap_update & sta_info_update23a */
1723                bss_cap_update_on_sta_join23a(padapter, pstat);
1724                sta_info_update23a(padapter, pstat);
1725
1726                /* issue assoc rsp before notify station join event. */
1727                if (ieee80211_is_assoc_req(mgmt->frame_control))
1728                        issue_assocrsp(padapter, status, pstat,
1729                                       IEEE80211_STYPE_ASSOC_RESP);
1730                else
1731                        issue_assocrsp(padapter, status, pstat,
1732                                       IEEE80211_STYPE_REASSOC_RESP);
1733
1734                /* 2 - report to upper layer */
1735                DBG_8723A("indicate_sta_join_event to upper layer - hostapd\n");
1736                rtw_cfg80211_indicate_sta_assoc(padapter, pframe, pkt_len);
1737
1738                /* 3-(1) report sta add event */
1739                report_add_sta_event23a(padapter, pstat->hwaddr, pstat->aid);
1740#endif
1741        }
1742
1743        return _SUCCESS;
1744
1745asoc_class2_error:
1746
1747#ifdef CONFIG_8723AU_AP_MODE
1748        issue_deauth23a(padapter, mgmt->sa, status);
1749#endif
1750        return _FAIL;
1751
1752OnAssocReq23aFail:
1753
1754#ifdef CONFIG_8723AU_AP_MODE
1755        pstat->aid = 0;
1756        if (ieee80211_is_assoc_req(mgmt->frame_control))
1757                issue_assocrsp(padapter, status, pstat,
1758                               IEEE80211_STYPE_ASSOC_RESP);
1759        else
1760                issue_assocrsp(padapter, status, pstat,
1761                               IEEE80211_STYPE_REASSOC_RESP);
1762#endif
1763
1764#endif /* CONFIG_8723AU_AP_MODE */
1765
1766        return _FAIL;
1767}
1768
1769static int
1770OnAssocRsp23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
1771{
1772        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1773        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
1774        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
1775        struct sk_buff *skb = precv_frame->pkt;
1776        struct ieee80211_mgmt *pmgmt = (struct ieee80211_mgmt *) skb->data;
1777        int res;
1778        unsigned short status;
1779        const u8 *p, *pie;
1780        u8 *pframe = skb->data;
1781        int pkt_len = skb->len;
1782        int pielen;
1783
1784        DBG_8723A("%s\n", __func__);
1785
1786        /* check A1 matches or not */
1787        if (!ether_addr_equal(myid(&padapter->eeprompriv), pmgmt->da))
1788                return _SUCCESS;
1789
1790        if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE)))
1791                return _SUCCESS;
1792
1793        if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)
1794                return _SUCCESS;
1795
1796        del_timer_sync(&pmlmeext->link_timer);
1797
1798        /* status */
1799        status = le16_to_cpu(pmgmt->u.assoc_resp.status_code);
1800        if (status > 0) {
1801                DBG_8723A("assoc reject, status code: %d\n", status);
1802                pmlmeinfo->state = MSR_NOLINK;
1803                res = -4;
1804                goto report_assoc_result;
1805        }
1806
1807        /* get capabilities */
1808        pmlmeinfo->capability = le16_to_cpu(pmgmt->u.assoc_resp.capab_info);
1809
1810        /* set slot time */
1811        pmlmeinfo->slotTime = (pmlmeinfo->capability & BIT(10))? 9: 20;
1812
1813        /* AID */
1814        res = pmlmeinfo->aid = le16_to_cpu(pmgmt->u.assoc_resp.aid) & 0x3fff;
1815
1816        pie = pframe + offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
1817        pielen = pkt_len -
1818                offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
1819
1820        p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY,
1821                             pmgmt->u.assoc_resp.variable, pielen);
1822        if (p && p[1])
1823                HT_caps_handler23a(padapter, p);
1824
1825        p = cfg80211_find_ie(WLAN_EID_HT_OPERATION,
1826                             pmgmt->u.assoc_resp.variable, pielen);
1827        if (p && p[1])
1828                HT_info_handler23a(padapter, p);
1829
1830        p = cfg80211_find_ie(WLAN_EID_ERP_INFO,
1831                             pmgmt->u.assoc_resp.variable, pielen);
1832        if (p && p[1])
1833                ERP_IE_handler23a(padapter, p);
1834
1835        pie = pframe + offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
1836        while (true) {
1837                p = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
1838                                            WLAN_OUI_TYPE_MICROSOFT_WMM,
1839                                            pie, pframe + pkt_len - pie);
1840                if (!p)
1841                        break;
1842
1843                pie = p + p[1] + 2;
1844                /* if this IE is too short, try the next */
1845                if (p[1] <= 4)
1846                        continue;
1847                /* if this IE is WMM params, we found what we wanted */
1848                if (p[6] == 1)
1849                        break;
1850        }
1851
1852        if (p && p[1])
1853                WMM_param_handler23a(padapter, p);
1854
1855        pmlmeinfo->state &= ~WIFI_FW_ASSOC_STATE;
1856        pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS;
1857
1858        /* Update Basic Rate Table for spec, 2010-12-28 , by thomas */
1859        UpdateBrateTbl23a(padapter, pmlmeinfo->network.SupportedRates);
1860
1861report_assoc_result:
1862        pmlmepriv->assoc_rsp_len = 0;
1863        if (res > 0) {
1864                kfree(pmlmepriv->assoc_rsp);
1865                pmlmepriv->assoc_rsp = kmalloc(pkt_len, GFP_ATOMIC);
1866                if (pmlmepriv->assoc_rsp) {
1867                        memcpy(pmlmepriv->assoc_rsp, pframe, pkt_len);
1868                        pmlmepriv->assoc_rsp_len = pkt_len;
1869                }
1870        } else
1871                kfree(pmlmepriv->assoc_rsp);
1872
1873        report_join_res23a(padapter, res);
1874
1875        return _SUCCESS;
1876}
1877
1878static int
1879OnDeAuth23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
1880{
1881        unsigned short reason;
1882        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1883        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
1884        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
1885        struct sk_buff *skb = precv_frame->pkt;
1886        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data;
1887
1888        if (!ether_addr_equal(mgmt->bssid,
1889                              get_my_bssid23a(&pmlmeinfo->network)))
1890                return _SUCCESS;
1891
1892        reason = le16_to_cpu(mgmt->u.deauth.reason_code);
1893
1894        DBG_8723A("%s Reason code(%d)\n", __func__, reason);
1895
1896#ifdef CONFIG_8723AU_AP_MODE
1897        if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
1898                struct sta_info *psta;
1899                struct sta_priv *pstapriv = &padapter->stapriv;
1900
1901                DBG_8723A_LEVEL(_drv_always_, "ap recv deauth reason code(%d) "
1902                                "sta:%pM\n", reason, mgmt->sa);
1903
1904                psta = rtw_get_stainfo23a(pstapriv, mgmt->sa);
1905                if (psta) {
1906                        u8 updated = 0;
1907
1908                        spin_lock_bh(&pstapriv->asoc_list_lock);
1909                        if (!list_empty(&psta->asoc_list)) {
1910                                list_del_init(&psta->asoc_list);
1911                                pstapriv->asoc_list_cnt--;
1912                                updated = ap_free_sta23a(padapter, psta,
1913                                                      false, reason);
1914                        }
1915                        spin_unlock_bh(&pstapriv->asoc_list_lock);
1916
1917                        associated_clients_update23a(padapter, updated);
1918                }
1919
1920                return _SUCCESS;
1921        } else
1922#endif
1923        {
1924                DBG_8723A_LEVEL(_drv_always_, "sta recv deauth reason code(%d) "
1925                                "sta:%pM\n", reason, mgmt->bssid);
1926
1927                receive_disconnect23a(padapter, mgmt->bssid, reason);
1928        }
1929        pmlmepriv->LinkDetectInfo.bBusyTraffic = false;
1930
1931        return _SUCCESS;
1932}
1933
1934static int
1935OnDisassoc23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
1936{
1937        unsigned short reason;
1938        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1939        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
1940        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
1941        struct sk_buff *skb = precv_frame->pkt;
1942        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data;
1943
1944        if (!ether_addr_equal(mgmt->bssid,
1945                              get_my_bssid23a(&pmlmeinfo->network)))
1946                return _SUCCESS;
1947
1948        reason = le16_to_cpu(mgmt->u.disassoc.reason_code);
1949
1950        DBG_8723A("%s Reason code(%d)\n", __func__, reason);
1951
1952#ifdef CONFIG_8723AU_AP_MODE
1953        if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
1954                struct sta_info *psta;
1955                struct sta_priv *pstapriv = &padapter->stapriv;
1956
1957                DBG_8723A_LEVEL(_drv_always_, "ap recv disassoc reason code(%d)"
1958                                " sta:%pM\n", reason, mgmt->sa);
1959
1960                psta = rtw_get_stainfo23a(pstapriv, mgmt->sa);
1961                if (psta) {
1962                        u8 updated = 0;
1963
1964                        spin_lock_bh(&pstapriv->asoc_list_lock);
1965                        if (!list_empty(&psta->asoc_list)) {
1966                                list_del_init(&psta->asoc_list);
1967                                pstapriv->asoc_list_cnt--;
1968                                updated = ap_free_sta23a(padapter, psta,
1969                                                         false, reason);
1970                        }
1971                        spin_unlock_bh(&pstapriv->asoc_list_lock);
1972
1973                        associated_clients_update23a(padapter, updated);
1974                }
1975
1976                return _SUCCESS;
1977        } else
1978#endif
1979        {
1980                DBG_8723A_LEVEL(_drv_always_, "ap recv disassoc reason "
1981                                "code(%d) sta:%pM\n", reason, mgmt->bssid);
1982
1983                receive_disconnect23a(padapter, mgmt->bssid, reason);
1984        }
1985        pmlmepriv->LinkDetectInfo.bBusyTraffic = false;
1986        return _SUCCESS;
1987}
1988
1989static int
1990OnAtim23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
1991{
1992        DBG_8723A("%s\n", __func__);
1993        return _SUCCESS;
1994}
1995
1996static int
1997on_action_spct23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
1998{
1999        return _FAIL;
2000}
2001
2002static int
2003OnAction23a_qos(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
2004{
2005        return _SUCCESS;
2006}
2007
2008static int
2009OnAction23a_dls(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
2010{
2011        return _SUCCESS;
2012}
2013
2014static int OnAction23a_back23a(struct rtw_adapter *padapter,
2015                               struct recv_frame *precv_frame)
2016{
2017        u8 *addr;
2018        struct sta_info *psta = NULL;
2019        struct recv_reorder_ctrl *preorder_ctrl;
2020        unsigned char category, action;
2021        unsigned short tid, status, capab, params, reason_code = 0;
2022        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
2023        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
2024        struct sk_buff *skb = precv_frame->pkt;
2025        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data;
2026        struct sta_priv *pstapriv = &padapter->stapriv;
2027
2028        /* check RA matches or not */
2029        if (!ether_addr_equal(myid(&padapter->eeprompriv), mgmt->da))
2030                return _SUCCESS;
2031
2032        DBG_8723A("%s\n", __func__);
2033
2034        if ((pmlmeinfo->state&0x03) != MSR_AP)
2035                if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS))
2036                        return _SUCCESS;
2037
2038        addr = mgmt->sa;
2039        psta = rtw_get_stainfo23a(pstapriv, addr);
2040
2041        if (!psta)
2042                return _SUCCESS;
2043
2044        category = mgmt->u.action.category;
2045        if (category == WLAN_CATEGORY_BACK) { /*  representing Block Ack */
2046                if (!pmlmeinfo->HT_enable)
2047                        return _SUCCESS;
2048                /* action_code is located in the same place for all
2049                   action events, so pick any */
2050                action = mgmt->u.action.u.wme_action.action_code;
2051                DBG_8723A("%s, action =%d\n", __func__, action);
2052                switch (action) {
2053                case WLAN_ACTION_ADDBA_REQ: /* ADDBA request */
2054                        memcpy(&pmlmeinfo->ADDBA_req,
2055                               &mgmt->u.action.u.addba_req.dialog_token,
2056                               sizeof(struct ADDBA_request));
2057                        process_addba_req23a(padapter,
2058                                             (u8 *)&pmlmeinfo->ADDBA_req, addr);
2059                        if (pmlmeinfo->bAcceptAddbaReq == true)
2060                                issue_action_BA23a(padapter, addr,
2061                                                   WLAN_ACTION_ADDBA_RESP, 0);
2062                        else {
2063                                /* reject ADDBA Req */
2064                                issue_action_BA23a(padapter, addr,
2065                                                   WLAN_ACTION_ADDBA_RESP, 37);
2066                        }
2067                        break;
2068                case WLAN_ACTION_ADDBA_RESP: /* ADDBA response */
2069                        status = get_unaligned_le16(
2070                                &mgmt->u.action.u.addba_resp.status);
2071                        capab = get_unaligned_le16(
2072                                &mgmt->u.action.u.addba_resp.capab);
2073                        tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
2074                        if (status == 0) {      /* successful */
2075                                DBG_8723A("agg_enable for TID =%d\n", tid);
2076                                psta->htpriv.agg_enable_bitmap |= BIT(tid);
2077                                psta->htpriv.candidate_tid_bitmap &= ~BIT(tid);
2078                        } else
2079                                psta->htpriv.agg_enable_bitmap &= ~BIT(tid);
2080                        break;
2081
2082                case WLAN_ACTION_DELBA: /* DELBA */
2083                        params = get_unaligned_le16(
2084                                &mgmt->u.action.u.delba.params);
2085                        tid = params >> 12;
2086
2087                        if (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) {
2088                                preorder_ctrl = &psta->recvreorder_ctrl[tid];
2089                                preorder_ctrl->enable = false;
2090                                preorder_ctrl->indicate_seq = 0xffff;
2091                        } else {
2092                                psta->htpriv.agg_enable_bitmap &= ~BIT(tid);
2093                                psta->htpriv.candidate_tid_bitmap &= ~BIT(tid);
2094                        }
2095                        reason_code = get_unaligned_le16(
2096                                &mgmt->u.action.u.delba.reason_code);
2097                        /* todo: how to notify the host while receiving
2098                           DELETE BA */
2099                        break;
2100                default:
2101                        break;
2102                }
2103        }
2104        return _SUCCESS;
2105}
2106
2107static int on_action_public23a(struct rtw_adapter *padapter,
2108                               struct recv_frame *precv_frame)
2109{
2110        struct sk_buff *skb = precv_frame->pkt;
2111        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
2112        u8 *pframe = skb->data;
2113        int freq, channel;
2114
2115        /* check RA matches or not */
2116        if (!ether_addr_equal(myid(&padapter->eeprompriv), hdr->addr1))
2117                return _FAIL;
2118
2119        channel = rtw_get_oper_ch23a(padapter);
2120
2121        if (channel <= RTW_CH_MAX_2G_CHANNEL)
2122                freq = ieee80211_channel_to_frequency(channel,
2123                                                      IEEE80211_BAND_2GHZ);
2124        else
2125                freq = ieee80211_channel_to_frequency(channel,
2126                                                      IEEE80211_BAND_5GHZ);
2127
2128        if (cfg80211_rx_mgmt(padapter->rtw_wdev, freq, 0, pframe,
2129                             skb->len, 0))
2130                return _SUCCESS;
2131
2132        return _FAIL;
2133}
2134
2135static int
2136OnAction23a_ht(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
2137{
2138        return _SUCCESS;
2139}
2140
2141static int
2142OnAction23a_wmm(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
2143{
2144        return _SUCCESS;
2145}
2146
2147static int
2148OnAction23a_p2p(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
2149{
2150        return _SUCCESS;
2151}
2152
2153static int
2154OnAction23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
2155{
2156        int i;
2157        u8 category;
2158        struct action_handler *ptable;
2159        struct sk_buff *skb = precv_frame->pkt;
2160        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data;
2161
2162        category = mgmt->u.action.category;
2163
2164        for (i = 0;
2165             i < sizeof(OnAction23a_tbl) / sizeof(struct action_handler); i++) {
2166                ptable = &OnAction23a_tbl[i];
2167
2168                if (category == ptable->num)
2169                        ptable->func(padapter, precv_frame);
2170        }
2171
2172        return _SUCCESS;
2173}
2174
2175static int DoReserved23a(struct rtw_adapter *padapter,
2176                         struct recv_frame *precv_frame)
2177{
2178        return _SUCCESS;
2179}
2180
2181struct xmit_frame *alloc_mgtxmitframe23a(struct xmit_priv *pxmitpriv)
2182{
2183        struct xmit_frame *pmgntframe;
2184        struct xmit_buf *pxmitbuf;
2185
2186        pmgntframe = rtw_alloc_xmitframe23a_ext(pxmitpriv);
2187
2188        if (!pmgntframe) {
2189                DBG_8723A("%s(%s): alloc xmitframe fail\n", __func__,
2190                          pxmitpriv->adapter->pnetdev->name);
2191                goto exit;
2192        }
2193
2194        pxmitbuf = rtw_alloc_xmitbuf23a_ext(pxmitpriv);
2195        if (!pxmitbuf) {
2196                DBG_8723A("%s(%s): alloc xmitbuf fail\n", __func__,
2197                          pxmitpriv->adapter->pnetdev->name);
2198                rtw_free_xmitframe23a(pxmitpriv, pmgntframe);
2199                pmgntframe = NULL;
2200                goto exit;
2201        }
2202
2203        pmgntframe->frame_tag = MGNT_FRAMETAG;
2204        pmgntframe->pxmitbuf = pxmitbuf;
2205        pmgntframe->buf_addr = pxmitbuf->pbuf;
2206        pxmitbuf->priv_data = pmgntframe;
2207
2208exit:
2209        return pmgntframe;
2210}
2211
2212/****************************************************************************
2213
2214Following are some TX functions for WiFi MLME
2215
2216*****************************************************************************/
2217
2218void update_mgnt_tx_rate23a(struct rtw_adapter *padapter, u8 rate)
2219{
2220        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
2221
2222        pmlmeext->tx_rate = rate;
2223        DBG_8723A("%s(): rate = %x\n", __func__, rate);
2224}
2225
2226void update_mgntframe_attrib23a(struct rtw_adapter *padapter,
2227                                struct pkt_attrib *pattrib)
2228{
2229        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
2230
2231        memset((u8 *)pattrib, 0, sizeof(struct pkt_attrib));
2232
2233        pattrib->hdrlen = 24;
2234        pattrib->nr_frags = 1;
2235        pattrib->priority = 7;
2236        pattrib->mac_id = 0;
2237        pattrib->qsel = 0x12;
2238
2239        pattrib->pktlen = 0;
2240
2241        if (pmlmeext->cur_wireless_mode & WIRELESS_11B)
2242                pattrib->raid = 6;/* b mode */
2243        else
2244                pattrib->raid = 5;/* a/g mode */
2245
2246        pattrib->encrypt = 0;
2247        pattrib->bswenc = false;
2248
2249        pattrib->qos_en = false;
2250        pattrib->ht_en = false;
2251        pattrib->bwmode = HT_CHANNEL_WIDTH_20;
2252        pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
2253        pattrib->sgi = false;
2254
2255        pattrib->seqnum = pmlmeext->mgnt_seq;
2256
2257        pattrib->retry_ctrl = true;
2258}
2259
2260void dump_mgntframe23a(struct rtw_adapter *padapter,
2261                       struct xmit_frame *pmgntframe)
2262{
2263        if (padapter->bSurpriseRemoved == true ||
2264            padapter->bDriverStopped == true)
2265                return;
2266
2267        rtl8723au_mgnt_xmit(padapter, pmgntframe);
2268}
2269
2270int dump_mgntframe23a_and_wait(struct rtw_adapter *padapter,
2271                               struct xmit_frame *pmgntframe, int timeout_ms)
2272{
2273        int ret = _FAIL;
2274        unsigned long irqL;
2275        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
2276        struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf;
2277        struct submit_ctx sctx;
2278
2279        if (padapter->bSurpriseRemoved == true ||
2280            padapter->bDriverStopped == true)
2281                return ret;
2282
2283        rtw_sctx_init23a(&sctx, timeout_ms);
2284        pxmitbuf->sctx = &sctx;
2285
2286        ret = rtl8723au_mgnt_xmit(padapter, pmgntframe);
2287
2288        if (ret == _SUCCESS)
2289                ret = rtw_sctx_wait23a(&sctx);
2290
2291        spin_lock_irqsave(&pxmitpriv->lock_sctx, irqL);
2292        pxmitbuf->sctx = NULL;
2293        spin_unlock_irqrestore(&pxmitpriv->lock_sctx, irqL);
2294
2295        return ret;
2296}
2297
2298int dump_mgntframe23a_and_wait_ack23a(struct rtw_adapter *padapter,
2299                                      struct xmit_frame *pmgntframe)
2300{
2301        int ret = _FAIL;
2302        u32 timeout_ms = 500;/*   500ms */
2303        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
2304
2305        if (padapter->bSurpriseRemoved == true ||
2306            padapter->bDriverStopped == true)
2307                return _FAIL;
2308
2309        mutex_lock(&pxmitpriv->ack_tx_mutex);
2310        pxmitpriv->ack_tx = true;
2311
2312        pmgntframe->ack_report = 1;
2313        if (rtl8723au_mgnt_xmit(padapter, pmgntframe) == _SUCCESS)
2314                ret = rtw_ack_tx_wait23a(pxmitpriv, timeout_ms);
2315
2316        pxmitpriv->ack_tx = false;
2317        mutex_unlock(&pxmitpriv->ack_tx_mutex);
2318
2319        return ret;
2320}
2321
2322static int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode)
2323{
2324        u8 *ssid_ie;
2325        int ssid_len_ori;
2326        int len_diff = 0;
2327        u8 *next_ie;
2328        u32 remain_len;
2329
2330        ssid_ie = rtw_get_ie23a(ies,  WLAN_EID_SSID, &ssid_len_ori, ies_len);
2331
2332        /* DBG_8723A("%s hidden_ssid_mode:%u, ssid_ie:%p, ssid_len_ori:%d\n",
2333           __func__, hidden_ssid_mode, ssid_ie, ssid_len_ori); */
2334
2335        if (ssid_ie && ssid_len_ori > 0) {
2336                switch (hidden_ssid_mode) {
2337                case 1:
2338                        next_ie = ssid_ie + 2 + ssid_len_ori;
2339                        remain_len = ies_len -(next_ie-ies);
2340
2341                        ssid_ie[1] = 0;
2342                        memcpy(ssid_ie+2, next_ie, remain_len);
2343                        len_diff -= ssid_len_ori;
2344
2345                        break;
2346                case 2:
2347                        memset(&ssid_ie[2], 0, ssid_len_ori);
2348                        break;
2349                default:
2350                        break;
2351                }
2352        }
2353
2354        return len_diff;
2355}
2356
2357void issue_beacon23a(struct rtw_adapter *padapter, int timeout_ms)
2358{
2359        struct xmit_frame *pmgntframe;
2360        struct pkt_attrib *pattrib;
2361        unsigned char *pframe;
2362        struct ieee80211_mgmt *mgmt;
2363        unsigned int rate_len;
2364        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
2365        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
2366        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
2367        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
2368        struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
2369        u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2370        const u8 *wps_ie;
2371        u8 sr = 0;
2372        int len_diff;
2373
2374        /* DBG_8723A("%s\n", __func__); */
2375
2376        pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
2377        if (!pmgntframe) {
2378                DBG_8723A("%s, alloc mgnt frame fail\n", __func__);
2379                return;
2380        }
2381#ifdef CONFIG_8723AU_AP_MODE
2382        spin_lock_bh(&pmlmepriv->bcn_update_lock);
2383#endif
2384
2385        /* update attribute */
2386        pattrib = &pmgntframe->attrib;
2387        update_mgntframe_attrib23a(padapter, pattrib);
2388        pattrib->qsel = 0x10;
2389
2390        memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
2391
2392        pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
2393        mgmt = (struct ieee80211_mgmt *)pframe;
2394
2395        mgmt->frame_control =
2396                cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
2397        mgmt->seq_ctrl = 0;
2398
2399        ether_addr_copy(mgmt->da, bc_addr);
2400        ether_addr_copy(mgmt->sa, myid(&padapter->eeprompriv));
2401        ether_addr_copy(mgmt->bssid, get_my_bssid23a(cur_network));
2402
2403        /* timestamp will be inserted by hardware */
2404
2405        put_unaligned_le16(cur_network->beacon_interval,
2406                           &mgmt->u.beacon.beacon_int);
2407
2408        put_unaligned_le16(cur_network->capability,
2409                           &mgmt->u.beacon.capab_info);
2410
2411        pframe = mgmt->u.beacon.variable;
2412        pattrib->pktlen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
2413
2414        if ((pmlmeinfo->state & 0x03) == MSR_AP) {
2415                u8 *iebuf;
2416                int buflen;
2417                /* DBG_8723A("ie len =%d\n", cur_network->IELength); */
2418                memcpy(pframe, cur_network->IEs, cur_network->IELength);
2419                len_diff = update_hidden_ssid(pframe, cur_network->IELength,
2420                                              pmlmeinfo->hidden_ssid_mode);
2421                pframe += (cur_network->IELength+len_diff);
2422                pattrib->pktlen += (cur_network->IELength+len_diff);
2423
2424                iebuf = mgmt->u.beacon.variable;
2425                buflen = pattrib->pktlen -
2426                        offsetof(struct ieee80211_mgmt, u.beacon.variable);
2427                wps_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
2428                                                 WLAN_OUI_TYPE_MICROSOFT_WPS,
2429                                                 iebuf, buflen);
2430
2431                if (wps_ie && wps_ie[1] > 0) {
2432                        rtw_get_wps_attr_content23a(wps_ie, wps_ie[1],
2433                                                    WPS_ATTR_SELECTED_REGISTRAR,
2434                                                    (u8 *)&sr);
2435                }
2436                if (sr != 0)
2437                        set_fwstate(pmlmepriv, WIFI_UNDER_WPS);
2438                else
2439                        _clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS);
2440
2441                goto _issue_bcn;
2442        }
2443
2444        /*  SSID */
2445        pframe = rtw_set_ie23a(pframe, WLAN_EID_SSID,
2446                               cur_network->Ssid.ssid_len,
2447                               cur_network->Ssid.ssid, &pattrib->pktlen);
2448
2449        /*  supported rates... */
2450        rate_len = rtw_get_rateset_len23a(cur_network->SupportedRates);
2451        pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES,
2452                               ((rate_len > 8)? 8: rate_len),
2453                               cur_network->SupportedRates, &pattrib->pktlen);
2454
2455        /*  DS parameter set */
2456        pframe = rtw_set_ie23a(pframe, WLAN_EID_DS_PARAMS, 1, (unsigned char *)
2457                               &cur_network->DSConfig, &pattrib->pktlen);
2458
2459        /* if ((pmlmeinfo->state&0x03) == MSR_ADHOC) */
2460        {
2461                u8 erpinfo = 0;
2462                u32 ATIMWindow;
2463                /*  IBSS Parameter Set... */
2464                /* ATIMWindow = cur->ATIMWindow; */
2465                ATIMWindow = 0;
2466                pframe = rtw_set_ie23a(pframe, WLAN_EID_IBSS_PARAMS, 2,
2467                                       (unsigned char *)&ATIMWindow,
2468                                       &pattrib->pktlen);
2469
2470                /* ERP IE */
2471                pframe = rtw_set_ie23a(pframe, WLAN_EID_ERP_INFO, 1,
2472                                       &erpinfo, &pattrib->pktlen);
2473        }
2474
2475        /*  EXTERNDED SUPPORTED RATE */
2476        if (rate_len > 8)
2477                pframe = rtw_set_ie23a(pframe, WLAN_EID_EXT_SUPP_RATES,
2478                                       rate_len - 8,
2479                                       cur_network->SupportedRates + 8,
2480                                       &pattrib->pktlen);
2481
2482        /* todo:HT for adhoc */
2483
2484_issue_bcn:
2485
2486#ifdef CONFIG_8723AU_AP_MODE
2487        pmlmepriv->update_bcn = false;
2488
2489        spin_unlock_bh(&pmlmepriv->bcn_update_lock);
2490#endif
2491
2492        if ((pattrib->pktlen + TXDESC_SIZE) > 512) {
2493                DBG_8723A("beacon frame too large\n");
2494                return;
2495        }
2496
2497        pattrib->last_txcmdsz = pattrib->pktlen;
2498
2499        /* DBG_8723A("issue bcn_sz =%d\n", pattrib->last_txcmdsz); */
2500        if (timeout_ms > 0)
2501                dump_mgntframe23a_and_wait(padapter, pmgntframe, timeout_ms);
2502        else
2503                dump_mgntframe23a(padapter, pmgntframe);
2504}
2505
2506static void issue_probersp(struct rtw_adapter *padapter, unsigned char *da,
2507                           u8 is_valid_p2p_probereq)
2508{
2509        struct xmit_frame *pmgntframe;
2510        struct pkt_attrib *pattrib;
2511        unsigned char *pframe;
2512        struct ieee80211_mgmt *mgmt;
2513        unsigned char *mac, *bssid;
2514        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
2515#ifdef CONFIG_8723AU_AP_MODE
2516        const u8 *pwps_ie;
2517        u8 *ssid_ie;
2518        int ssid_ielen;
2519        int ssid_ielen_diff;
2520        u8 buf[MAX_IE_SZ];
2521#endif
2522        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
2523        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
2524        struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
2525        unsigned int rate_len;
2526
2527        /* DBG_8723A("%s\n", __func__); */
2528
2529        if (cur_network->IELength > MAX_IE_SZ)
2530                return;
2531
2532        pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
2533        if (!pmgntframe) {
2534                DBG_8723A("%s, alloc mgnt frame fail\n", __func__);
2535                return;
2536        }
2537
2538        /* update attribute */
2539        pattrib = &pmgntframe->attrib;
2540        update_mgntframe_attrib23a(padapter, pattrib);
2541
2542        memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
2543
2544        pframe = (u8 *)pmgntframe->buf_addr + TXDESC_OFFSET;
2545        mgmt = (struct ieee80211_mgmt *)pframe;
2546
2547        mac = myid(&padapter->eeprompriv);
2548        bssid = cur_network->MacAddress;
2549
2550        mgmt->frame_control =
2551                cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP);
2552
2553        ether_addr_copy(mgmt->da, da);
2554        ether_addr_copy(mgmt->sa, mac);
2555        ether_addr_copy(mgmt->bssid, bssid);
2556
2557        mgmt->seq_ctrl = cpu_to_le16(IEEE80211_SN_TO_SEQ(pmlmeext->mgnt_seq));
2558        pmlmeext->mgnt_seq++;
2559
2560        pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr);
2561
2562        /* timestamp will be inserted by hardware */
2563        put_unaligned_le16(cur_network->beacon_interval,
2564                           &mgmt->u.probe_resp.beacon_int);
2565
2566        put_unaligned_le16(cur_network->capability,
2567                           &mgmt->u.probe_resp.capab_info);
2568
2569        pframe = mgmt->u.probe_resp.variable;
2570        pattrib->pktlen =
2571                offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
2572
2573        /* below for ad-hoc mode */
2574
2575#ifdef CONFIG_8723AU_AP_MODE
2576        if ((pmlmeinfo->state & 0x03) == MSR_AP) {
2577                pwps_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
2578                                                  WLAN_OUI_TYPE_MICROSOFT_WPS,
2579                                                  cur_network->IEs,
2580                                                  cur_network->IELength);
2581
2582                memcpy(pframe, cur_network->IEs, cur_network->IELength);
2583                pframe += cur_network->IELength;
2584                pattrib->pktlen += cur_network->IELength;
2585
2586                /* retrieve SSID IE from cur_network->Ssid */
2587
2588                ssid_ie = rtw_get_ie23a(mgmt->u.probe_resp.variable,
2589                                        WLAN_EID_SSID, &ssid_ielen,
2590                                        pframe - mgmt->u.probe_resp.variable);
2591
2592                ssid_ielen_diff = cur_network->Ssid.ssid_len - ssid_ielen;
2593
2594                if (ssid_ie && cur_network->Ssid.ssid_len) {
2595                        uint remainder_ielen;
2596                        u8 *remainder_ie;
2597
2598                        remainder_ie = ssid_ie + 2;
2599
2600                        remainder_ielen = pframe - remainder_ie;
2601
2602                        DBG_8723A_LEVEL(_drv_warning_, "%s(%s): "
2603                                        "remainder_ielen > MAX_IE_SZ\n",
2604                                        __func__, padapter->pnetdev->name);
2605                        if (remainder_ielen > MAX_IE_SZ)
2606                                remainder_ielen = MAX_IE_SZ;
2607
2608                        memcpy(buf, remainder_ie, remainder_ielen);
2609                        memcpy(remainder_ie + ssid_ielen_diff, buf,
2610                               remainder_ielen);
2611                        *(ssid_ie + 1) = cur_network->Ssid.ssid_len;
2612                        memcpy(ssid_ie + 2, cur_network->Ssid.ssid,
2613                               cur_network->Ssid.ssid_len);
2614
2615                        pframe += ssid_ielen_diff;
2616                        pattrib->pktlen += ssid_ielen_diff;
2617                }
2618        } else
2619#endif
2620        {
2621                /*  SSID */
2622                pframe = rtw_set_ie23a(pframe, WLAN_EID_SSID,
2623                                       cur_network->Ssid.ssid_len,
2624                                       cur_network->Ssid.ssid,
2625                                       &pattrib->pktlen);
2626
2627                /*  supported rates... */
2628                rate_len = rtw_get_rateset_len23a(cur_network->SupportedRates);
2629                pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES,
2630                                       ((rate_len > 8)? 8: rate_len),
2631                                       cur_network->SupportedRates,
2632                                       &pattrib->pktlen);
2633
2634                /*  DS parameter set */
2635                pframe = rtw_set_ie23a(pframe, WLAN_EID_DS_PARAMS, 1,
2636                                       (unsigned char *)&cur_network->DSConfig,
2637                                       &pattrib->pktlen);
2638
2639                if ((pmlmeinfo->state & 0x03) == MSR_ADHOC) {
2640                        u8 erpinfo = 0;
2641                        u32 ATIMWindow;
2642                        /*  IBSS Parameter Set... */
2643                        /* ATIMWindow = cur->ATIMWindow; */
2644                        ATIMWindow = 0;
2645                        pframe = rtw_set_ie23a(pframe, WLAN_EID_IBSS_PARAMS, 2,
2646                                               (unsigned char *)&ATIMWindow,
2647                                               &pattrib->pktlen);
2648
2649                        /* ERP IE */
2650                        pframe = rtw_set_ie23a(pframe, WLAN_EID_ERP_INFO, 1,
2651                                               &erpinfo, &pattrib->pktlen);
2652                }
2653
2654                /*  EXTERNDED SUPPORTED RATE */
2655                if (rate_len > 8)
2656                        pframe = rtw_set_ie23a(pframe, WLAN_EID_EXT_SUPP_RATES,
2657                                               rate_len - 8,
2658                                               cur_network->SupportedRates + 8,
2659                                               &pattrib->pktlen);
2660
2661                /* todo:HT for adhoc */
2662        }
2663
2664        pattrib->last_txcmdsz = pattrib->pktlen;
2665
2666        dump_mgntframe23a(padapter, pmgntframe);
2667
2668        return;
2669}
2670
2671static int _issue_probereq(struct rtw_adapter *padapter,
2672                           struct cfg80211_ssid *pssid, u8 *da, int wait_ack)
2673{
2674        int ret = _FAIL;
2675        struct xmit_frame *pmgntframe;
2676        struct pkt_attrib *pattrib;
2677        unsigned char *pframe;
2678        struct ieee80211_hdr *pwlanhdr;
2679        unsigned char *mac;
2680        unsigned char bssrate[NumRates];
2681        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
2682        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
2683        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
2684        int bssrate_len = 0;
2685        u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2686
2687        RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
2688                 "+%s\n", __func__);
2689
2690        pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
2691        if (!pmgntframe)
2692                goto exit;
2693
2694        /* update attribute */
2695        pattrib = &pmgntframe->attrib;
2696        update_mgntframe_attrib23a(padapter, pattrib);
2697
2698        memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
2699
2700        pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
2701        pwlanhdr = (struct ieee80211_hdr *)pframe;
2702
2703        mac = myid(&padapter->eeprompriv);
2704
2705        pwlanhdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2706                                              IEEE80211_STYPE_PROBE_REQ);
2707
2708        if (da) {
2709                /*      unicast probe request frame */
2710                ether_addr_copy(pwlanhdr->addr1, da);
2711                ether_addr_copy(pwlanhdr->addr3, da);
2712        } else {
2713                /*      broadcast probe request frame */
2714                ether_addr_copy(pwlanhdr->addr1, bc_addr);
2715                ether_addr_copy(pwlanhdr->addr3, bc_addr);
2716        }
2717
2718        ether_addr_copy(pwlanhdr->addr2, mac);
2719
2720        pwlanhdr->seq_ctrl =
2721                cpu_to_le16(IEEE80211_SN_TO_SEQ(pmlmeext->mgnt_seq));
2722
2723        pmlmeext->mgnt_seq++;
2724
2725        pframe += sizeof (struct ieee80211_hdr_3addr);
2726        pattrib->pktlen = sizeof (struct ieee80211_hdr_3addr);
2727
2728        if (pssid)
2729                pframe = rtw_set_ie23a(pframe, WLAN_EID_SSID, pssid->ssid_len,
2730                                       pssid->ssid, &pattrib->pktlen);
2731        else
2732                pframe = rtw_set_ie23a(pframe, WLAN_EID_SSID, 0, NULL,
2733                                       &pattrib->pktlen);
2734
2735        get_rate_set23a(padapter, bssrate, &bssrate_len);
2736
2737        if (bssrate_len > 8) {
2738                pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES, 8,
2739                                       bssrate, &pattrib->pktlen);
2740                pframe = rtw_set_ie23a(pframe, WLAN_EID_EXT_SUPP_RATES,
2741                                       (bssrate_len - 8), (bssrate + 8),
2742                                       &pattrib->pktlen);
2743        } else {
2744                pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES,
2745                                       bssrate_len, bssrate, &pattrib->pktlen);
2746        }
2747
2748        /* add wps_ie for wps2.0 */
2749        if (pmlmepriv->wps_probe_req_ie_len>0 && pmlmepriv->wps_probe_req_ie) {
2750                memcpy(pframe, pmlmepriv->wps_probe_req_ie,
2751                       pmlmepriv->wps_probe_req_ie_len);
2752                pframe += pmlmepriv->wps_probe_req_ie_len;
2753                pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len;
2754        }
2755
2756        pattrib->last_txcmdsz = pattrib->pktlen;
2757
2758        RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
2759                 "issuing probe_req, tx_len =%d\n", pattrib->last_txcmdsz);
2760
2761        if (wait_ack) {
2762                ret = dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe);
2763        } else {
2764                dump_mgntframe23a(padapter, pmgntframe);
2765                ret = _SUCCESS;
2766        }
2767
2768exit:
2769        return ret;
2770}
2771
2772static inline void issue_probereq(struct rtw_adapter *padapter,
2773                                  struct cfg80211_ssid *pssid, u8 *da)
2774{
2775        _issue_probereq(padapter, pssid, da, false);
2776}
2777
2778static int issue_probereq_ex(struct rtw_adapter *padapter,
2779                             struct cfg80211_ssid *pssid, u8 *da,
2780                             int try_cnt, int wait_ms)
2781{
2782        int ret;
2783        int i = 0;
2784        unsigned long start = jiffies;
2785
2786        do {
2787                ret = _issue_probereq(padapter, pssid, da,
2788                                      wait_ms > 0 ? true : false);
2789
2790                i++;
2791
2792                if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
2793                        break;
2794
2795                if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
2796                        msleep(wait_ms);
2797
2798        } while((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
2799
2800        if (ret != _FAIL) {
2801                ret = _SUCCESS;
2802                goto exit;
2803        }
2804
2805        if (try_cnt && wait_ms) {
2806                if (da)
2807                        DBG_8723A("%s(%s): to %pM, ch:%u%s, %d/%d in %u ms\n",
2808                                  __func__, padapter->pnetdev->name,
2809                                  da, rtw_get_oper_ch23a(padapter),
2810                                  ret == _SUCCESS ? ", acked" : "", i, try_cnt,
2811                                  jiffies_to_msecs(jiffies - start));
2812                else
2813                        DBG_8723A("%s(%s):, ch:%u%s, %d/%d in %u ms\n",
2814                                  __func__, padapter->pnetdev->name,
2815                                  rtw_get_oper_ch23a(padapter),
2816                                  ret == _SUCCESS ? ", acked" : "", i, try_cnt,
2817                                  jiffies_to_msecs(jiffies - start));
2818        }
2819exit:
2820        return ret;
2821}
2822
2823/*  if psta == NULL, indiate we are station(client) now... */
2824static void issue_auth(struct rtw_adapter *padapter, struct sta_info *psta,
2825                       unsigned short status)
2826{
2827        struct xmit_frame *pmgntframe;
2828        struct pkt_attrib *pattrib;
2829        unsigned char *pframe;
2830        struct ieee80211_mgmt *mgmt;
2831        unsigned int val32;
2832        u16 auth_algo;
2833        int use_shared_key = 0;
2834        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
2835        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
2836        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
2837
2838        pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
2839        if (!pmgntframe)
2840                return;
2841
2842        /* update attribute */
2843        pattrib = &pmgntframe->attrib;
2844        update_mgntframe_attrib23a(padapter, pattrib);
2845
2846        memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
2847
2848        pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
2849        mgmt = (struct ieee80211_mgmt *)pframe;
2850
2851        mgmt->frame_control =
2852                cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
2853        mgmt->seq_ctrl = cpu_to_le16(IEEE80211_SN_TO_SEQ(pmlmeext->mgnt_seq));
2854        pmlmeext->mgnt_seq++;
2855
2856        pattrib->pktlen = offsetof(struct ieee80211_mgmt, u.auth.variable);
2857
2858        if (psta) { /*  for AP mode */
2859#ifdef CONFIG_8723AU_AP_MODE
2860                unsigned short val16;
2861
2862                ether_addr_copy(mgmt->da, psta->hwaddr);
2863                ether_addr_copy(mgmt->sa, myid(&padapter->eeprompriv));
2864                ether_addr_copy(mgmt->bssid, myid(&padapter->eeprompriv));
2865
2866                /*  setting auth algo number */
2867                val16 = (u16)psta->authalg;
2868
2869                if (status != WLAN_STATUS_SUCCESS)
2870                        val16 = 0;
2871
2872                if (val16)
2873                        use_shared_key = 1;
2874
2875                mgmt->u.auth.auth_alg = cpu_to_le16(val16);
2876
2877                /*  setting auth seq number */
2878                mgmt->u.auth.auth_transaction =
2879                        cpu_to_le16((u16)psta->auth_seq);
2880
2881                /*  setting status code... */
2882                mgmt->u.auth.status_code = cpu_to_le16(status);
2883
2884                pframe = mgmt->u.auth.variable;
2885                /*  added challenging text... */
2886                if ((psta->auth_seq == 2) &&
2887                    (psta->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1))
2888                        pframe = rtw_set_ie23a(pframe, WLAN_EID_CHALLENGE, 128,
2889                                               psta->chg_txt, &pattrib->pktlen);
2890#endif
2891        } else {
2892                struct ieee80211_mgmt *iv_mgmt;
2893
2894                ether_addr_copy(mgmt->da, get_my_bssid23a(&pmlmeinfo->network));
2895                ether_addr_copy(mgmt->sa, myid(&padapter->eeprompriv));
2896                ether_addr_copy(mgmt->bssid,
2897                                get_my_bssid23a(&pmlmeinfo->network));
2898
2899                /*  setting auth algo number */
2900                /*  0:OPEN System, 1:Shared key */
2901                if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) {
2902                        use_shared_key = 1;
2903                        auth_algo = WLAN_AUTH_SHARED_KEY;
2904                } else
2905                        auth_algo = WLAN_AUTH_OPEN;
2906
2907                /* DBG_8723A("%s auth_algo = %s auth_seq =%d\n", __func__,
2908                   (pmlmeinfo->auth_algo == 0)?"OPEN":"SHARED",
2909                   pmlmeinfo->auth_seq); */
2910
2911                /* setting IV for auth seq #3 */
2912                if ((pmlmeinfo->auth_seq == 3) &&
2913                    (pmlmeinfo->state & WIFI_FW_AUTH_STATE) &&
2914                    (use_shared_key == 1)) {
2915                        u32 *piv = (u32 *)&mgmt->u.auth;
2916
2917                        iv_mgmt = (struct ieee80211_mgmt *)(pframe + 4);
2918                        /* DBG_8723A("==> iv(%d), key_index(%d)\n",
2919                           pmlmeinfo->iv, pmlmeinfo->key_index); */
2920                        val32 = (pmlmeinfo->iv & 0x3fffffff) |
2921                                (pmlmeinfo->key_index << 30);
2922                        pmlmeinfo->iv++;
2923                        put_unaligned_le32(val32, piv);
2924
2925                        pattrib->pktlen += 4;
2926
2927                        pattrib->iv_len = IEEE80211_WEP_IV_LEN;
2928                } else
2929                        iv_mgmt = mgmt;
2930
2931                iv_mgmt->u.auth.auth_alg = cpu_to_le16(auth_algo);
2932
2933                /*  setting auth seq number */
2934                iv_mgmt->u.auth.auth_transaction =
2935                        cpu_to_le16(pmlmeinfo->auth_seq);
2936
2937                /*  setting status code... */
2938                iv_mgmt->u.auth.status_code = cpu_to_le16(status);
2939
2940                pframe = iv_mgmt->u.auth.variable;
2941
2942                /*  then checking to see if sending challenging text... */
2943                if ((pmlmeinfo->auth_seq == 3) &&
2944                    (pmlmeinfo->state & WIFI_FW_AUTH_STATE) &&
2945                    (use_shared_key == 1)) {
2946                        pframe = rtw_set_ie23a(pframe, WLAN_EID_CHALLENGE, 128,
2947                                               pmlmeinfo->chg_txt,
2948                                               &pattrib->pktlen);
2949
2950                        mgmt->frame_control |=
2951                                cpu_to_le16(IEEE80211_FCTL_PROTECTED);
2952
2953                        pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr);
2954
2955                        pattrib->encrypt = WLAN_CIPHER_SUITE_WEP40;
2956
2957                        pattrib->icv_len = IEEE80211_WEP_ICV_LEN;
2958
2959                        pattrib->pktlen += pattrib->icv_len;
2960                }
2961        }
2962
2963        pattrib->last_txcmdsz = pattrib->pktlen;
2964
2965        rtw_wep_encrypt23a(padapter, pmgntframe);
2966        DBG_8723A("%s\n", __func__);
2967        dump_mgntframe23a(padapter, pmgntframe);
2968
2969        return;
2970}
2971
2972#ifdef CONFIG_8723AU_AP_MODE
2973static void issue_assocrsp(struct rtw_adapter *padapter, unsigned short status,
2974                           struct sta_info *pstat, u16 pkt_type)
2975{
2976        struct xmit_frame *pmgntframe;
2977        struct ieee80211_mgmt *mgmt;
2978        struct pkt_attrib *pattrib;
2979        unsigned char *pframe;
2980        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
2981        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
2982        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
2983        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
2984        struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
2985        const u8 *p;
2986        u8 *ie = pnetwork->IEs;
2987
2988        DBG_8723A("%s\n", __func__);
2989
2990        pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
2991        if (!pmgntframe)
2992                return;
2993
2994        /* update attribute */
2995        pattrib = &pmgntframe->attrib;
2996        update_mgntframe_attrib23a(padapter, pattrib);
2997
2998        memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
2999
3000        pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
3001        mgmt = (struct ieee80211_mgmt *)pframe;
3002
3003        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | pkt_type);
3004
3005        ether_addr_copy(mgmt->da, pstat->hwaddr);
3006        ether_addr_copy(mgmt->sa, myid(&padapter->eeprompriv));
3007        ether_addr_copy(mgmt->bssid, get_my_bssid23a(&pmlmeinfo->network));
3008
3009        mgmt->seq_ctrl = cpu_to_le16(IEEE80211_SN_TO_SEQ(pmlmeext->mgnt_seq));
3010
3011        pmlmeext->mgnt_seq++;
3012
3013        pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr);
3014        pattrib->pktlen =
3015                offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
3016
3017        mgmt->u.assoc_resp.capab_info = cpu_to_le16(pnetwork->capability);
3018        mgmt->u.assoc_resp.status_code = cpu_to_le16(status);
3019        mgmt->u.assoc_resp.aid = cpu_to_le16(pstat->aid | BIT(14) | BIT(15));
3020
3021        pframe = mgmt->u.assoc_resp.variable;
3022
3023        if (pstat->bssratelen <= 8) {
3024                pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES,
3025                                       pstat->bssratelen, pstat->bssrateset,
3026                                       &pattrib->pktlen);
3027        } else {
3028                pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES, 8,
3029                                       pstat->bssrateset, &pattrib->pktlen);
3030                pframe = rtw_set_ie23a(pframe, WLAN_EID_EXT_SUPP_RATES,
3031                                       pstat->bssratelen - 8,
3032                                       pstat->bssrateset + 8, &pattrib->pktlen);
3033        }
3034
3035        if (pstat->flags & WLAN_STA_HT && pmlmepriv->htpriv.ht_option) {
3036                /* FILL HT CAP INFO IE */
3037                /* p = hostapd_eid_ht_capabilities_info(hapd, p); */
3038                p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ie,
3039                                     pnetwork->IELength);
3040                if (p && p[1]) {
3041                        memcpy(pframe, p, p[1] + 2);
3042                        pframe += (p[1] + 2);
3043                        pattrib->pktlen += (p[1] + 2);
3044                }
3045
3046                /* FILL HT ADD INFO IE */
3047                /* p = hostapd_eid_ht_operation(hapd, p); */
3048                p = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ie,
3049                                     pnetwork->IELength);
3050                if (p && p[1] > 0) {
3051                        memcpy(pframe, p, p[1] + 2);
3052                        pframe += (p[1] + 2);
3053                        pattrib->pktlen += (p[1] + 2);
3054                }
3055        }
3056
3057        /* FILL WMM IE */
3058        if (pstat->flags & WLAN_STA_WME && pmlmepriv->qos_option) {
3059                unsigned char WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02,
3060                                               0x01, 0x01};
3061                int ie_len = 0;
3062
3063                for (p = ie; ; p += (ie_len + 2)) {
3064                        p = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, p,
3065                                             pnetwork->IELength - (ie_len + 2));
3066                        if (p)
3067                                ie_len = p[1];
3068                        else
3069                                ie_len = 0;
3070                        if (p && !memcmp(p + 2, WMM_PARA_IE, 6)) {
3071                                memcpy(pframe, p, ie_len + 2);
3072                                pframe += (ie_len + 2);
3073                                pattrib->pktlen += (ie_len + 2);
3074
3075                                break;
3076                        }
3077
3078                        if (!p || ie_len == 0)
3079                                break;
3080                }
3081        }
3082
3083        if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) {
3084                pframe = rtw_set_ie23a(pframe, WLAN_EID_VENDOR_SPECIFIC, 6,
3085                                       REALTEK_96B_IE, &pattrib->pktlen);
3086        }
3087
3088        pattrib->last_txcmdsz = pattrib->pktlen;
3089
3090        dump_mgntframe23a(padapter, pmgntframe);
3091}
3092#endif
3093
3094static void issue_assocreq(struct rtw_adapter *padapter)
3095{
3096        int ret = _FAIL;
3097        struct xmit_frame *pmgntframe;
3098        struct pkt_attrib *pattrib;
3099        unsigned char *pframe;
3100        const u8 *p;
3101        struct ieee80211_mgmt *mgmt;
3102        unsigned int i, j, index = 0;
3103        unsigned char rf_type, bssrate[NumRates], sta_bssrate[NumRates];
3104        struct registry_priv *pregpriv = &padapter->registrypriv;
3105        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
3106        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
3107        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
3108        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
3109        int bssrate_len = 0, sta_bssrate_len = 0, pie_len;
3110        u8 *pie;
3111
3112        pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
3113        if (!pmgntframe)
3114                goto exit;
3115
3116        /* update attribute */
3117        pattrib = &pmgntframe->attrib;
3118        update_mgntframe_attrib23a(padapter, pattrib);
3119
3120        memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
3121
3122        pframe = (u8 *)pmgntframe->buf_addr + TXDESC_OFFSET;
3123        mgmt = (struct ieee80211_mgmt *)pframe;
3124
3125        mgmt->frame_control =
3126                cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ASSOC_REQ);
3127
3128        ether_addr_copy(mgmt->da, get_my_bssid23a(&pmlmeinfo->network));
3129        ether_addr_copy(mgmt->sa, myid(&padapter->eeprompriv));
3130        ether_addr_copy(mgmt->bssid, get_my_bssid23a(&pmlmeinfo->network));
3131
3132        mgmt->seq_ctrl = cpu_to_le16(IEEE80211_SN_TO_SEQ(pmlmeext->mgnt_seq));
3133        pmlmeext->mgnt_seq++;
3134
3135        /* caps */
3136        put_unaligned_le16(pmlmeinfo->network.capability,
3137                           &mgmt->u.assoc_req.capab_info);
3138        /* todo: listen interval for power saving */
3139        put_unaligned_le16(3, &mgmt->u.assoc_req.listen_interval);
3140
3141        pframe = mgmt->u.assoc_req.variable;
3142        pattrib->pktlen = offsetof(struct ieee80211_mgmt, u.assoc_req.variable);
3143
3144        /* SSID */
3145        pframe = rtw_set_ie23a(pframe, WLAN_EID_SSID,
3146                               pmlmeinfo->network.Ssid.ssid_len,
3147                               pmlmeinfo->network.Ssid.ssid, &pattrib->pktlen);
3148
3149        /* supported rate & extended supported rate */
3150
3151        get_rate_set23a(padapter, sta_bssrate, &sta_bssrate_len);
3152        /* DBG_8723A("sta_bssrate_len =%d\n", sta_bssrate_len); */
3153
3154        /*  for JAPAN, channel 14 can only uses B Mode(CCK) */
3155        if (pmlmeext->cur_channel == 14)
3156                sta_bssrate_len = 4;
3157
3158        /* for (i = 0; i < sta_bssrate_len; i++) { */
3159        /*      DBG_8723A("sta_bssrate[%d]=%02X\n", i, sta_bssrate[i]); */
3160        /*  */
3161
3162        for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
3163                if (pmlmeinfo->network.SupportedRates[i] == 0)
3164                        break;
3165                DBG_8723A("network.SupportedRates[%d]=%02X\n", i,
3166                          pmlmeinfo->network.SupportedRates[i]);
3167        }
3168
3169        for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
3170                if (pmlmeinfo->network.SupportedRates[i] == 0)
3171                        break;
3172
3173                /*  Check if the AP's supported rates are also
3174                    supported by STA. */
3175                for (j = 0; j < sta_bssrate_len; j++) {
3176                         /*  Avoid the proprietary data rate (22Mbps) of
3177                             Handlink WSG-4000 AP */
3178                        if ((pmlmeinfo->network.SupportedRates[i] |
3179                             IEEE80211_BASIC_RATE_MASK) ==
3180                            (sta_bssrate[j] | IEEE80211_BASIC_RATE_MASK)) {
3181                                /* DBG_8723A("match i = %d, j =%d\n", i, j); */
3182                                break;
3183                        }
3184                }
3185
3186                if (j == sta_bssrate_len) {
3187                        /*  the rate is not supported by STA */
3188                        DBG_8723A("%s(): the rate[%d]=%02X is not supported by "
3189                                  "STA!\n", __func__, i,
3190                                  pmlmeinfo->network.SupportedRates[i]);
3191                } else {
3192                        /*  the rate is supported by STA */
3193                        bssrate[index++] = pmlmeinfo->network.SupportedRates[i];
3194                }
3195        }
3196
3197        bssrate_len = index;
3198        DBG_8723A("bssrate_len = %d\n", bssrate_len);
3199
3200        if (bssrate_len == 0) {
3201                rtw_free_xmitbuf23a(pxmitpriv, pmgntframe->pxmitbuf);
3202                rtw_free_xmitframe23a(pxmitpriv, pmgntframe);
3203                goto exit; /* don't connect to AP if no joint supported rate */
3204        }
3205
3206        if (bssrate_len > 8) {
3207                pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES, 8,
3208                                       bssrate, &pattrib->pktlen);
3209                pframe = rtw_set_ie23a(pframe, WLAN_EID_EXT_SUPP_RATES,
3210                                       (bssrate_len - 8), (bssrate + 8),
3211                                       &pattrib->pktlen);
3212        } else
3213                pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES,
3214                                       bssrate_len, bssrate, &pattrib->pktlen);
3215
3216        /* RSN */
3217
3218        pie = pmlmeinfo->network.IEs;
3219        pie_len = pmlmeinfo->network.IELength;
3220
3221        p = cfg80211_find_ie(WLAN_EID_RSN, pie, pie_len);
3222        if (p)
3223                pframe = rtw_set_ie23a(pframe, WLAN_EID_RSN, p[1], p + 2,
3224                                       &pattrib->pktlen);
3225
3226        /* HT caps */
3227        if (padapter->mlmepriv.htpriv.ht_option) {
3228                p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, pie, pie_len);
3229
3230                if (p && !is_ap_in_tkip23a(padapter)) {
3231                        struct ieee80211_ht_cap *cap = &pmlmeinfo->ht_cap;
3232
3233                        memcpy(cap, p + 2, sizeof(struct ieee80211_ht_cap));
3234
3235                        /* to disable 40M Hz support while gd_bw_40MHz_en = 0 */
3236                        if (pregpriv->cbw40_enable == 0) {
3237                                cap->cap_info &= ~cpu_to_le16(
3238                                        IEEE80211_HT_CAP_SGI_40 |
3239                                        IEEE80211_HT_CAP_SUP_WIDTH_20_40);
3240                        } else {
3241                                cap->cap_info |= cpu_to_le16(
3242                                        IEEE80211_HT_CAP_SUP_WIDTH_20_40);
3243                        }
3244
3245                        /* todo: disable SM power save mode */
3246                        cap->cap_info |= cpu_to_le16(IEEE80211_HT_CAP_SM_PS);
3247
3248                        rf_type = rtl8723a_get_rf_type(padapter);
3249                        /* switch (pregpriv->rf_config) */
3250                        switch (rf_type) {
3251                        case RF_1T1R:
3252                                /* RX STBC One spatial stream */
3253                                if (pregpriv->rx_stbc)
3254                                        cap->cap_info |= cpu_to_le16(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
3255
3256                                memcpy(&cap->mcs, MCS_rate_1R23A, 16);
3257                                break;
3258
3259                        case RF_2T2R:
3260                        case RF_1T2R:
3261                        default:
3262                                /* enable for 2.4/5 GHz */
3263                                if (pregpriv->rx_stbc == 0x3 ||
3264                                    (pmlmeext->cur_wireless_mode &
3265                                     WIRELESS_11_24N &&
3266                                     /* enable for 2.4GHz */
3267                                     pregpriv->rx_stbc == 0x1) ||
3268                                    (pmlmeext->cur_wireless_mode &
3269                                     WIRELESS_11_5N &&
3270                                     pregpriv->rx_stbc == 0x2) ||
3271                                    /* enable for 5GHz */
3272                                    pregpriv->wifi_spec == 1) {
3273                                        DBG_8723A("declare supporting RX "
3274                                                  "STBC\n");
3275                                        /* RX STBC two spatial stream */
3276                                        cap->cap_info |= cpu_to_le16(2 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
3277                                }
3278                                memcpy(&cap->mcs, MCS_rate_2R23A, 16);
3279                                break;
3280                        }
3281
3282                        if (rtl8723a_BT_coexist(padapter) &&
3283                            rtl8723a_BT_using_antenna_1(padapter)) {
3284                                /*  set to 8K */
3285                                cap->ampdu_params_info &=
3286                                        ~IEEE80211_HT_AMPDU_PARM_FACTOR;
3287/*                              cap->ampdu_params_info |= MAX_AMPDU_FACTOR_8K */
3288                        }
3289
3290                        pframe = rtw_set_ie23a(pframe, WLAN_EID_HT_CAPABILITY,
3291                                               p[1], (u8 *)&pmlmeinfo->ht_cap,
3292                                               &pattrib->pktlen);
3293                }
3294        }
3295
3296        /* vendor specific IE, such as WPA, WMM, WPS */
3297        for (i = 0;  i < pmlmeinfo->network.IELength;) {
3298                p = pmlmeinfo->network.IEs + i;
3299
3300                switch (p[0]) {
3301                case WLAN_EID_VENDOR_SPECIFIC:
3302                        if (!memcmp(p + 2, RTW_WPA_OUI23A_TYPE, 4) ||
3303                            !memcmp(p + 2, WMM_OUI23A, 4) ||
3304                            !memcmp(p + 2, WPS_OUI23A, 4)) {
3305                                u8 plen = p[1];
3306
3307                                if (!padapter->registrypriv.wifi_spec) {
3308                                        /* Commented by Kurt 20110629 */
3309                                        /* In some older APs, WPS handshake */
3310                                        /* would be fail if we append vender
3311                                           extensions informations to AP */
3312                                        if (!memcmp(p + 2, WPS_OUI23A, 4))
3313                                                plen = 14;
3314                                }
3315                                pframe = rtw_set_ie23a(pframe,
3316                                                       WLAN_EID_VENDOR_SPECIFIC,
3317                                                       plen, p + 2,
3318                                                       &pattrib->pktlen);
3319                        }
3320                        break;
3321
3322                default:
3323                        break;
3324                }
3325
3326                i += p[1] + 2;
3327        }
3328
3329        if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK)
3330                pframe = rtw_set_ie23a(pframe, WLAN_EID_VENDOR_SPECIFIC, 6,
3331                                       REALTEK_96B_IE, &pattrib->pktlen);
3332
3333        pattrib->last_txcmdsz = pattrib->pktlen;
3334        dump_mgntframe23a(padapter, pmgntframe);
3335
3336        ret = _SUCCESS;
3337
3338exit:
3339        pmlmepriv->assoc_req_len = 0;
3340        if (ret == _SUCCESS) {
3341                kfree(pmlmepriv->assoc_req);
3342                pmlmepriv->assoc_req = kmalloc(pattrib->pktlen, GFP_ATOMIC);
3343                if (pmlmepriv->assoc_req) {
3344                        memcpy(pmlmepriv->assoc_req, mgmt, pattrib->pktlen);
3345                        pmlmepriv->assoc_req_len = pattrib->pktlen;
3346                }
3347        } else
3348                kfree(pmlmepriv->assoc_req);
3349
3350        return;
3351}
3352
3353/* when wait_ack is true, this function should be called at process context */
3354static int _issue_nulldata23a(struct rtw_adapter *padapter, unsigned char *da,
3355                              unsigned int power_mode, int wait_ack)
3356{
3357        int ret = _FAIL;
3358        struct xmit_frame *pmgntframe;
3359        struct pkt_attrib *pattrib;
3360        unsigned char *pframe;
3361        struct ieee80211_hdr *pwlanhdr;
3362        struct xmit_priv *pxmitpriv;
3363        struct mlme_ext_priv *pmlmeext;
3364        struct mlme_ext_info *pmlmeinfo;
3365
3366        /* DBG_8723A("%s:%d\n", __func__, power_mode); */
3367
3368        if (!padapter)
3369                goto exit;
3370
3371        pxmitpriv = &padapter->xmitpriv;
3372        pmlmeext = &padapter->mlmeextpriv;
3373        pmlmeinfo = &pmlmeext->mlmext_info;
3374
3375        pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
3376        if (!pmgntframe)
3377                goto exit;
3378
3379        /* update attribute */
3380        pattrib = &pmgntframe->attrib;
3381        update_mgntframe_attrib23a(padapter, pattrib);
3382        pattrib->retry_ctrl = false;
3383
3384        memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
3385
3386        pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
3387        pwlanhdr = (struct ieee80211_hdr *)pframe;
3388
3389        pwlanhdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
3390                                              IEEE80211_STYPE_NULLFUNC);
3391
3392        if ((pmlmeinfo->state&0x03) == MSR_AP)
3393                pwlanhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
3394        else if ((pmlmeinfo->state&0x03) == MSR_INFRA)
3395                pwlanhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_TODS);
3396
3397        if (power_mode)
3398                pwlanhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
3399
3400        ether_addr_copy(pwlanhdr->addr1, da);
3401        ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
3402        ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network));
3403
3404        pwlanhdr->seq_ctrl =
3405                cpu_to_le16(IEEE80211_SN_TO_SEQ(pmlmeext->mgnt_seq));
3406        pmlmeext->mgnt_seq++;
3407
3408        pframe += sizeof(struct ieee80211_hdr_3addr);
3409        pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
3410
3411        pattrib->last_txcmdsz = pattrib->pktlen;
3412
3413        if (wait_ack)
3414                ret = dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe);
3415        else {
3416                dump_mgntframe23a(padapter, pmgntframe);
3417                ret = _SUCCESS;
3418        }
3419
3420exit:
3421        return ret;
3422}
3423
3424/* when wait_ms >0 , this function should be called at process context */
3425/* da == NULL for station mode */
3426int issue_nulldata23a(struct rtw_adapter *padapter, unsigned char *da,
3427                      unsigned int power_mode, int try_cnt, int wait_ms)
3428{
3429        int ret;
3430        int i = 0;
3431        unsigned long start = jiffies;
3432        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
3433        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
3434
3435        /* da == NULL, assume it's null data for sta to ap*/
3436        if (da == NULL)
3437                da = get_my_bssid23a(&pmlmeinfo->network);
3438
3439        do {
3440                ret = _issue_nulldata23a(padapter, da, power_mode,
3441                                         wait_ms > 0 ? true : false);
3442
3443                i++;
3444
3445                if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
3446                        break;
3447
3448                if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
3449                        msleep(wait_ms);
3450
3451        } while((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
3452
3453        if (ret != _FAIL) {
3454                ret = _SUCCESS;
3455                goto exit;
3456        }
3457
3458        if (try_cnt && wait_ms) {
3459                if (da)
3460                        DBG_8723A("%s(%s): to %pM, ch:%u%s, %d/%d in %u ms\n",
3461                                  __func__, padapter->pnetdev->name,
3462                                  da, rtw_get_oper_ch23a(padapter),
3463                                  ret == _SUCCESS ? ", acked" : "", i, try_cnt,
3464                                  jiffies_to_msecs(jiffies - start));
3465                else
3466                        DBG_8723A("%s(%s):, ch:%u%s, %d/%d in %u ms\n",
3467                                  __func__, padapter->pnetdev->name,
3468                                  rtw_get_oper_ch23a(padapter),
3469                                  ret == _SUCCESS ? ", acked" : "", i, try_cnt,
3470                                  jiffies_to_msecs(jiffies - start));
3471        }
3472exit:
3473        return ret;
3474}
3475
3476/* when wait_ack is true, this function should be called at process context */
3477static int _issue_qos_nulldata23a(struct rtw_adapter *padapter,
3478                                  unsigned char *da, u16 tid, int wait_ack)
3479{
3480        int ret = _FAIL;
3481        struct xmit_frame *pmgntframe;
3482        struct pkt_attrib *pattrib;
3483        unsigned char *pframe;
3484        struct ieee80211_qos_hdr *pwlanhdr;
3485        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
3486        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
3487        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
3488
3489        DBG_8723A("%s\n", __func__);
3490
3491        pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
3492        if (!pmgntframe)
3493                goto exit;
3494
3495        /* update attribute */
3496        pattrib = &pmgntframe->attrib;
3497        update_mgntframe_attrib23a(padapter, pattrib);
3498
3499        pattrib->hdrlen += 2;
3500        pattrib->qos_en = true;
3501        pattrib->eosp = 1;
3502        pattrib->ack_policy = 0;
3503        pattrib->mdata = 0;
3504
3505        memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
3506
3507        pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
3508        pwlanhdr = (struct ieee80211_qos_hdr *)pframe;
3509
3510        pwlanhdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
3511                                              IEEE80211_STYPE_QOS_NULLFUNC);
3512
3513        if ((pmlmeinfo->state&0x03) == MSR_AP)
3514                pwlanhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
3515        else if ((pmlmeinfo->state&0x03) == MSR_INFRA)
3516                pwlanhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_TODS);
3517
3518        if (pattrib->mdata)
3519                pwlanhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
3520
3521        pwlanhdr->qos_ctrl = cpu_to_le16(tid & IEEE80211_QOS_CTL_TID_MASK);
3522        pwlanhdr->qos_ctrl |= cpu_to_le16((pattrib->ack_policy << 5) &
3523                                          IEEE80211_QOS_CTL_ACK_POLICY_MASK);
3524        if (pattrib->eosp)
3525                pwlanhdr->qos_ctrl |= cpu_to_le16(IEEE80211_QOS_CTL_EOSP);
3526
3527        ether_addr_copy(pwlanhdr->addr1, da);
3528        ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
3529        ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network));
3530
3531        pwlanhdr->seq_ctrl =
3532                cpu_to_le16(IEEE80211_SN_TO_SEQ(pmlmeext->mgnt_seq));
3533        pmlmeext->mgnt_seq++;
3534
3535        pframe += sizeof(struct ieee80211_qos_hdr);
3536        pattrib->pktlen = sizeof(struct ieee80211_qos_hdr);
3537
3538        pattrib->last_txcmdsz = pattrib->pktlen;
3539
3540        if (wait_ack)
3541                ret = dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe);
3542        else {
3543                dump_mgntframe23a(padapter, pmgntframe);
3544                ret = _SUCCESS;
3545        }
3546
3547exit:
3548        return ret;
3549}
3550
3551/* when wait_ms >0 , this function should be called at process context */
3552/* da == NULL for station mode */
3553int issue_qos_nulldata23a(struct rtw_adapter *padapter, unsigned char *da,
3554                          u16 tid, int try_cnt, int wait_ms)
3555{
3556        int ret;
3557        int i = 0;
3558        unsigned long start = jiffies;
3559        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
3560        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
3561
3562        /* da == NULL, assume it's null data for sta to ap*/
3563        if (da == NULL)
3564                da = get_my_bssid23a(&pmlmeinfo->network);
3565
3566        do {
3567                ret = _issue_qos_nulldata23a(padapter, da, tid,
3568                                             wait_ms > 0 ? true : false);
3569
3570                i++;
3571
3572                if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
3573                        break;
3574
3575                if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
3576                        msleep(wait_ms);
3577        } while((i < try_cnt) && ((ret == _FAIL)||(wait_ms == 0)));
3578
3579        if (ret != _FAIL) {
3580                ret = _SUCCESS;
3581                goto exit;
3582        }
3583
3584        if (try_cnt && wait_ms) {
3585                if (da)
3586                        DBG_8723A("%s(%s): to %pM, ch:%u%s, %d/%d in %u ms\n",
3587                                  __func__, padapter->pnetdev->name,
3588                                  da, rtw_get_oper_ch23a(padapter),
3589                                  ret == _SUCCESS ? ", acked" : "", i, try_cnt,
3590                                  jiffies_to_msecs(jiffies - start));
3591                else
3592                        DBG_8723A("%s(%s):, ch:%u%s, %d/%d in %u ms\n",
3593                                  __func__, padapter->pnetdev->name,
3594                                  rtw_get_oper_ch23a(padapter),
3595                                  ret == _SUCCESS ? ", acked" : "", i, try_cnt,
3596                                  jiffies_to_msecs(jiffies - start));
3597        }
3598exit:
3599        return ret;
3600}
3601
3602static int _issue_deauth(struct rtw_adapter *padapter, unsigned char *da,
3603                         unsigned short reason, u8 wait_ack)
3604{
3605        struct xmit_frame *pmgntframe;
3606        struct pkt_attrib *pattrib;
3607        struct ieee80211_mgmt *mgmt;
3608        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
3609        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
3610        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
3611        int ret = _FAIL;
3612
3613        /* DBG_8723A("%s to %pM\n", __func__, da); */
3614
3615        pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
3616        if (!pmgntframe)
3617                goto exit;
3618
3619        /* update attribute */
3620        pattrib = &pmgntframe->attrib;
3621        update_mgntframe_attrib23a(padapter, pattrib);
3622        pattrib->retry_ctrl = false;
3623
3624        memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
3625
3626        mgmt = (struct ieee80211_mgmt *)(pmgntframe->buf_addr + TXDESC_OFFSET);
3627
3628        mgmt->frame_control =
3629                cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH);
3630
3631        ether_addr_copy(mgmt->da, da);
3632        ether_addr_copy(mgmt->sa, myid(&padapter->eeprompriv));
3633        ether_addr_copy(mgmt->bssid, get_my_bssid23a(&pmlmeinfo->network));
3634
3635        mgmt->seq_ctrl = cpu_to_le16(IEEE80211_SN_TO_SEQ(pmlmeext->mgnt_seq));
3636        pmlmeext->mgnt_seq++;
3637
3638        pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr) + 2;
3639
3640        mgmt->u.deauth.reason_code = cpu_to_le16(reason);
3641
3642        pattrib->last_txcmdsz = pattrib->pktlen;
3643
3644        if (wait_ack)
3645                ret = dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe);
3646        else {
3647                dump_mgntframe23a(padapter, pmgntframe);
3648                ret = _SUCCESS;
3649        }
3650
3651exit:
3652        return ret;
3653}
3654
3655int issue_deauth23a(struct rtw_adapter *padapter, unsigned char *da,
3656                    unsigned short reason)
3657{
3658        DBG_8723A("%s to %pM\n", __func__, da);
3659        return _issue_deauth(padapter, da, reason, false);
3660}
3661
3662static int issue_deauth_ex(struct rtw_adapter *padapter, u8 *da,
3663                           unsigned short reason, int try_cnt, int wait_ms)
3664{
3665        int ret;
3666        int i = 0;
3667        unsigned long start = jiffies;
3668
3669        do {
3670                ret = _issue_deauth(padapter, da, reason,
3671                                    wait_ms >0 ? true : false);
3672
3673                i++;
3674
3675                if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
3676                        break;
3677
3678                if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
3679                        msleep(wait_ms);
3680
3681        } while((i < try_cnt) && ((ret == _FAIL)||(wait_ms == 0)));
3682
3683        if (ret != _FAIL) {
3684                ret = _SUCCESS;
3685                goto exit;
3686        }
3687
3688        if (try_cnt && wait_ms) {
3689                if (da)
3690                        DBG_8723A("%s(%s): to %pM, ch:%u%s, %d/%d in %u ms\n",
3691                                  __func__, padapter->pnetdev->name,
3692                                  da, rtw_get_oper_ch23a(padapter),
3693                                  ret == _SUCCESS ? ", acked" : "", i, try_cnt,
3694                                  jiffies_to_msecs(jiffies - start));
3695                else
3696                        DBG_8723A("%s(%s):, ch:%u%s, %d/%d in %u ms\n",
3697                                  __func__, padapter->pnetdev->name,
3698                                  rtw_get_oper_ch23a(padapter),
3699                                  ret == _SUCCESS ? ", acked" : "", i, try_cnt,
3700                                  jiffies_to_msecs(jiffies - start));
3701        }
3702exit:
3703        return ret;
3704}
3705
3706void issue_action_spct_ch_switch23a(struct rtw_adapter *padapter,
3707                                    u8 *ra, u8 new_ch, u8 ch_offset)
3708{
3709        struct xmit_frame *pmgntframe;
3710        struct pkt_attrib *pattrib;
3711        unsigned char *pframe;
3712        struct ieee80211_mgmt *mgmt;
3713        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
3714        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
3715
3716        DBG_8723A("%s(%s): ra=%pM, ch:%u, offset:%u\n",
3717                  __func__, padapter->pnetdev->name, ra, new_ch, ch_offset);
3718
3719        pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
3720        if (!pmgntframe)
3721                return;
3722
3723        /* update attribute */
3724        pattrib = &pmgntframe->attrib;
3725        update_mgntframe_attrib23a(padapter, pattrib);
3726
3727        memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
3728
3729        mgmt = (struct ieee80211_mgmt *)(pmgntframe->buf_addr + TXDESC_OFFSET);
3730
3731        mgmt->frame_control =
3732                cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
3733
3734        ether_addr_copy(mgmt->da, ra); /* RA */
3735        ether_addr_copy(mgmt->sa, myid(&padapter->eeprompriv)); /* TA */
3736        ether_addr_copy(mgmt->bssid, ra); /* DA = RA */
3737
3738        mgmt->seq_ctrl = cpu_to_le16(IEEE80211_SN_TO_SEQ(pmlmeext->mgnt_seq));
3739        pmlmeext->mgnt_seq++;
3740
3741        mgmt->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
3742        mgmt->u.action.u.chan_switch.action_code = WLAN_ACTION_SPCT_CHL_SWITCH;
3743
3744        pframe = mgmt->u.action.u.chan_switch.variable;
3745        pattrib->pktlen = offsetof(struct ieee80211_mgmt,
3746                                   u.action.u.chan_switch.variable);
3747
3748        pframe = rtw_set_ie23a_ch_switch (pframe, &pattrib->pktlen, 0,
3749                                          new_ch, 0);
3750        pframe = rtw_set_ie23a_secondary_ch_offset(pframe, &pattrib->pktlen,
3751                hal_ch_offset_to_secondary_ch_offset23a(ch_offset));
3752
3753        pattrib->last_txcmdsz = pattrib->pktlen;
3754
3755        dump_mgntframe23a(padapter, pmgntframe);
3756}
3757
3758void issue_action_BA23a(struct rtw_adapter *padapter,
3759                        const unsigned char *raddr,
3760                        unsigned char action, unsigned short status)
3761{
3762        u16 start_seq;
3763        u16 BA_para_set;
3764        u16 BA_starting_seqctrl;
3765        u16 BA_para;
3766        int max_rx_ampdu_factor;
3767        struct xmit_frame *pmgntframe;
3768        struct pkt_attrib *pattrib;
3769        struct ieee80211_mgmt *mgmt;
3770        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
3771        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
3772        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
3773        struct sta_info *psta;
3774        struct sta_priv *pstapriv = &padapter->stapriv;
3775        struct registry_priv *pregpriv = &padapter->registrypriv;
3776        u8 tendaAPMac[] = {0xC8, 0x3A, 0x35};
3777
3778        DBG_8723A("%s, action =%d, status =%d\n", __func__, action, status);
3779
3780        pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
3781        if (!pmgntframe)
3782                return;
3783
3784        /* update attribute */
3785        pattrib = &pmgntframe->attrib;
3786        update_mgntframe_attrib23a(padapter, pattrib);
3787
3788        memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
3789
3790        mgmt = (struct ieee80211_mgmt *)(pmgntframe->buf_addr + TXDESC_OFFSET);
3791
3792        mgmt->frame_control =
3793                cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
3794
3795        ether_addr_copy(mgmt->da, raddr);
3796        ether_addr_copy(mgmt->sa, myid(&padapter->eeprompriv));
3797        ether_addr_copy(mgmt->bssid, get_my_bssid23a(&pmlmeinfo->network));
3798
3799        mgmt->seq_ctrl = cpu_to_le16(IEEE80211_SN_TO_SEQ(pmlmeext->mgnt_seq));
3800        pmlmeext->mgnt_seq++;
3801
3802        mgmt->u.action.category = WLAN_CATEGORY_BACK;
3803
3804        pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr) + 1;
3805
3806        status = cpu_to_le16(status);
3807
3808        switch (action) {
3809        case WLAN_ACTION_ADDBA_REQ:
3810                pattrib->pktlen += sizeof(mgmt->u.action.u.addba_req);
3811
3812                mgmt->u.action.u.addba_req.action_code = action;
3813
3814                do {
3815                        pmlmeinfo->dialogToken++;
3816                } while (pmlmeinfo->dialogToken == 0);
3817
3818                mgmt->u.action.u.addba_req.dialog_token =
3819                        pmlmeinfo->dialogToken;
3820
3821                if (rtl8723a_BT_coexist(padapter) &&
3822                    rtl8723a_BT_using_antenna_1(padapter) &&
3823                    (pmlmeinfo->assoc_AP_vendor != broadcomAP ||
3824                     memcmp(raddr, tendaAPMac, 3))) {
3825                        /*  A-MSDU NOT Supported */
3826                        BA_para_set = 0;
3827                        /*  immediate Block Ack */
3828                        BA_para_set |= (1 << 1) &
3829                                IEEE80211_ADDBA_PARAM_POLICY_MASK;
3830                        /*  TID */
3831                        BA_para_set |= (status << 2) &
3832                                IEEE80211_ADDBA_PARAM_TID_MASK;
3833                        /*  max buffer size is 8 MSDU */
3834                        BA_para_set |= (8 << 6) &
3835                                IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
3836                } else {
3837                        /* immediate ack & 64 buffer size */
3838                        BA_para_set = 0x1002 | ((status & 0xf) << 2);
3839                }
3840
3841                put_unaligned_le16(BA_para_set,
3842                                   &mgmt->u.action.u.addba_req.capab);
3843
3844                /*  5ms */
3845                put_unaligned_le16(5000, &mgmt->u.action.u.addba_req.timeout);
3846
3847                psta = rtw_get_stainfo23a(pstapriv, raddr);
3848                if (psta) {
3849                        int idx;
3850
3851                        idx = status & 0x07;
3852                        start_seq =
3853                                (psta->sta_xmitpriv.txseq_tid[idx] & 0xfff) + 1;
3854
3855                        DBG_8723A("BA_starting_seqctrl = %d for TID =%d\n",
3856                                  start_seq, idx);
3857
3858                        psta->BA_starting_seqctrl[idx] = start_seq;
3859
3860                        BA_starting_seqctrl = start_seq << 4;
3861                } else
3862                        BA_starting_seqctrl = 0;
3863
3864                put_unaligned_le16(BA_starting_seqctrl,
3865                                   &mgmt->u.action.u.addba_req.start_seq_num);
3866
3867                break;
3868
3869        case WLAN_ACTION_ADDBA_RESP:
3870                pattrib->pktlen += sizeof(mgmt->u.action.u.addba_resp);
3871
3872                mgmt->u.action.u.addba_resp.action_code = action;
3873                mgmt->u.action.u.addba_resp.dialog_token =
3874                        pmlmeinfo->ADDBA_req.dialog_token;
3875                put_unaligned_le16(status,
3876                                   &mgmt->u.action.u.addba_resp.status);
3877
3878                GetHalDefVar8192CUsb(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR,
3879                                     &max_rx_ampdu_factor);
3880
3881                BA_para = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f;
3882                if (max_rx_ampdu_factor == IEEE80211_HT_MAX_AMPDU_64K)
3883                        BA_para_set = BA_para | 0x1000; /* 64 buffer size */
3884                else if (max_rx_ampdu_factor == IEEE80211_HT_MAX_AMPDU_32K)
3885                        BA_para_set = BA_para | 0x0800; /* 32 buffer size */
3886                else if (max_rx_ampdu_factor == IEEE80211_HT_MAX_AMPDU_16K)
3887                        BA_para_set = BA_para | 0x0400; /* 16 buffer size */
3888                else if (max_rx_ampdu_factor == IEEE80211_HT_MAX_AMPDU_8K)
3889                        BA_para_set = BA_para | 0x0200; /* 8 buffer size */
3890                else
3891                        BA_para_set = BA_para | 0x1000; /* 64 buffer size */
3892
3893                if (rtl8723a_BT_coexist(padapter) &&
3894                    rtl8723a_BT_using_antenna_1(padapter) &&
3895                    (pmlmeinfo->assoc_AP_vendor != broadcomAP ||
3896                     memcmp(raddr, tendaAPMac, 3))) {
3897                        /*  max buffer size is 8 MSDU */
3898                        BA_para_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
3899                        BA_para_set |= (8 << 6) &
3900                                IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
3901                }
3902
3903                if (pregpriv->ampdu_amsdu == 0)/* disabled */
3904                        BA_para_set &= ~BIT(0);
3905                else if (pregpriv->ampdu_amsdu == 1)/* enabled */
3906                        BA_para_set |= BIT(0);
3907
3908                put_unaligned_le16(BA_para_set,
3909                                   &mgmt->u.action.u.addba_resp.capab);
3910
3911                put_unaligned_le16(pmlmeinfo->ADDBA_req.BA_timeout_value,
3912                                   &mgmt->u.action.u.addba_resp.timeout);
3913
3914                pattrib->pktlen += 8;
3915                break;
3916        case WLAN_ACTION_DELBA:
3917                pattrib->pktlen += sizeof(mgmt->u.action.u.delba);
3918
3919                mgmt->u.action.u.delba.action_code = action;
3920                BA_para_set = (status & 0x1F) << 3;
3921                mgmt->u.action.u.delba.params = cpu_to_le16(BA_para_set);
3922                mgmt->u.action.u.delba.reason_code =
3923                        cpu_to_le16(WLAN_REASON_QSTA_NOT_USE);
3924
3925                pattrib->pktlen += 5;
3926                break;
3927        default:
3928                break;
3929        }
3930
3931        pattrib->last_txcmdsz = pattrib->pktlen;
3932
3933        dump_mgntframe23a(padapter, pmgntframe);
3934}
3935
3936int send_delba23a(struct rtw_adapter *padapter, u8 initiator, u8 *addr)
3937{
3938        struct sta_priv *pstapriv = &padapter->stapriv;
3939        struct sta_info *psta = NULL;
3940        /* struct recv_reorder_ctrl *preorder_ctrl; */
3941        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
3942        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
3943        u16 tid;
3944
3945        if ((pmlmeinfo->state&0x03) != MSR_AP)
3946                if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS))
3947                        return _SUCCESS;
3948
3949        psta = rtw_get_stainfo23a(pstapriv, addr);
3950        if (psta == NULL)
3951                return _SUCCESS;
3952
3953        if (initiator == 0) {  /*  recipient */
3954                for (tid = 0; tid < MAXTID; tid++) {
3955                        if (psta->recvreorder_ctrl[tid].enable == true) {
3956                                DBG_8723A("rx agg disable tid(%d)\n", tid);
3957                                issue_action_BA23a(padapter, addr, WLAN_ACTION_DELBA, (((tid <<1) |initiator)&0x1F));
3958                                psta->recvreorder_ctrl[tid].enable = false;
3959                                psta->recvreorder_ctrl[tid].indicate_seq = 0xffff;
3960                        }
3961                }
3962        } else if (initiator == 1) { /*  originator */
3963                for (tid = 0; tid < MAXTID; tid++) {
3964                        if (psta->htpriv.agg_enable_bitmap & BIT(tid)) {
3965                                DBG_8723A("tx agg disable tid(%d)\n", tid);
3966                                issue_action_BA23a(padapter, addr, WLAN_ACTION_DELBA, (((tid <<1) |initiator)&0x1F));
3967                                psta->htpriv.agg_enable_bitmap &= ~BIT(tid);
3968                                psta->htpriv.candidate_tid_bitmap &= ~BIT(tid);
3969
3970                        }
3971                }
3972        }
3973        return _SUCCESS;
3974}
3975
3976int send_beacon23a(struct rtw_adapter *padapter)
3977{
3978        bool bxmitok;
3979        int issue = 0;
3980        int poll = 0;
3981        unsigned long start = jiffies;
3982        unsigned int passing_time;
3983
3984        rtl8723a_bcn_valid(padapter);
3985        do {
3986                issue_beacon23a(padapter, 100);
3987                issue++;
3988                do {
3989                        yield();
3990                        bxmitok = rtl8723a_get_bcn_valid(padapter);
3991                        poll++;
3992                } while ((poll % 10) != 0 && !bxmitok &&
3993                         !padapter->bSurpriseRemoved &&
3994                         !padapter->bDriverStopped);
3995
3996        } while (!bxmitok && issue<100 && !padapter->bSurpriseRemoved &&
3997                 !padapter->bDriverStopped);
3998
3999        if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
4000                return _FAIL;
4001
4002        passing_time = jiffies_to_msecs(jiffies - start);
4003
4004        if (!bxmitok) {
4005                DBG_8723A("%s fail! %u ms\n", __func__, passing_time);
4006                return _FAIL;
4007        } else {
4008
4009                if (passing_time > 100 || issue > 3)
4010                        DBG_8723A("%s success, issue:%d, poll:%d, %u ms\n",
4011                                  __func__, issue, poll, passing_time);
4012                return _SUCCESS;
4013        }
4014}
4015
4016/****************************************************************************
4017
4018Following are some utitity functions for WiFi MLME
4019
4020*****************************************************************************/
4021
4022bool IsLegal5GChannel(struct rtw_adapter *Adapter, u8 channel)
4023{
4024
4025        int i = 0;
4026        u8 Channel_5G[45] = {36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58,
4027                             60, 62, 64, 100, 102, 104, 106, 108, 110, 112,
4028                             114, 116, 118, 120, 122, 124, 126, 128, 130, 132,
4029                             134, 136, 138, 140, 149, 151, 153, 155, 157, 159,
4030                             161, 163, 165};
4031        for (i = 0; i < sizeof(Channel_5G); i++)
4032                if (channel == Channel_5G[i])
4033                        return true;
4034        return false;
4035}
4036
4037static void rtw_site_survey(struct rtw_adapter *padapter)
4038{
4039        unsigned char survey_channel = 0;
4040        enum rt_scan_type ScanType = SCAN_PASSIVE;
4041        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
4042        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
4043        struct rtw_ieee80211_channel *ch;
4044
4045        if (pmlmeext->sitesurvey_res.channel_idx <
4046            pmlmeext->sitesurvey_res.ch_num) {
4047                ch = &pmlmeext->sitesurvey_res.ch[pmlmeext->sitesurvey_res.channel_idx];
4048                survey_channel = ch->hw_value;
4049                ScanType = (ch->flags & IEEE80211_CHAN_NO_IR) ?
4050                        SCAN_PASSIVE : SCAN_ACTIVE;
4051        }
4052
4053        if (survey_channel != 0) {
4054                /* PAUSE 4-AC Queue when site_survey */
4055                if (pmlmeext->sitesurvey_res.channel_idx == 0)
4056                        set_channel_bwmode23a(padapter, survey_channel,
4057                                              HAL_PRIME_CHNL_OFFSET_DONT_CARE,
4058                                              HT_CHANNEL_WIDTH_20);
4059                else
4060                        SelectChannel23a(padapter, survey_channel);
4061
4062                if (ScanType == SCAN_ACTIVE) /* obey the channel plan setting... */
4063                {
4064                        int i;
4065
4066                        for (i = 0;i<RTW_SSID_SCAN_AMOUNT;i++) {
4067                                if (pmlmeext->sitesurvey_res.ssid[i].ssid_len) {
4068                                        /* todo: to issue two probe req??? */
4069                                        issue_probereq(padapter, &pmlmeext->sitesurvey_res.ssid[i], NULL);
4070                                        /* msleep(SURVEY_TO>>1); */
4071                                        issue_probereq(padapter, &pmlmeext->sitesurvey_res.ssid[i], NULL);
4072                                }
4073                        }
4074
4075                        if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) {
4076                                /* todo: to issue two probe req??? */
4077                                issue_probereq(padapter, NULL, NULL);
4078                                /* msleep(SURVEY_TO>>1); */
4079                                issue_probereq(padapter, NULL, NULL);
4080                        }
4081                }
4082
4083                set_survey_timer(pmlmeext, pmlmeext->chan_scan_time);
4084        } else {
4085                /*      channel number is 0 or this channel is not valid. */
4086                pmlmeext->sitesurvey_res.state = SCAN_COMPLETE;
4087
4088                /* switch back to the original channel */
4089
4090                set_channel_bwmode23a(padapter, pmlmeext->cur_channel,
4091                                      pmlmeext->cur_ch_offset,
4092                                      pmlmeext->cur_bwmode);
4093
4094                /* flush 4-AC Queue after rtw_site_survey */
4095                /* val8 = 0; */
4096
4097                /* config MSR */
4098                rtl8723a_set_media_status(padapter, pmlmeinfo->state & 0x3);
4099
4100                /* restore RX GAIN */
4101                rtl8723a_set_initial_gain(padapter, 0xff);
4102                /* turn on dynamic functions */
4103                rtl8723a_odm_support_ability_restore(padapter);
4104
4105                if (is_client_associated_to_ap23a(padapter) == true)
4106                        issue_nulldata23a(padapter, NULL, 0, 3, 500);
4107
4108                rtl8723a_mlme_sitesurvey(padapter, 0);
4109
4110                report_surveydone_event23a(padapter);
4111
4112                pmlmeext->chan_scan_time = SURVEY_TO;
4113                pmlmeext->sitesurvey_res.state = SCAN_DISABLE;
4114        }
4115
4116        return;
4117}
4118
4119/* collect bss info from Beacon and Probe request/response frames. */
4120static struct wlan_bssid_ex *collect_bss_info(struct rtw_adapter *padapter,
4121                                              struct recv_frame *precv_frame)
4122{
4123        struct sk_buff *skb = precv_frame->pkt;
4124        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data;
4125        struct registry_priv *pregistrypriv = &padapter->registrypriv;
4126        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
4127        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
4128        struct wlan_bssid_ex *bssid;
4129        const u8 *p;
4130        u8 *pie;
4131        unsigned int length;
4132        int i;
4133
4134        length = skb->len;
4135
4136        bssid = kzalloc(sizeof(struct wlan_bssid_ex), GFP_ATOMIC);
4137        if (!bssid)
4138                return NULL;
4139
4140        if (ieee80211_is_beacon(mgmt->frame_control)) {
4141                length -= offsetof(struct ieee80211_mgmt, u.beacon.variable);
4142                pie = mgmt->u.beacon.variable;
4143                bssid->reserved = 1;
4144                bssid->capability =
4145                        get_unaligned_le16(&mgmt->u.beacon.capab_info);
4146                bssid->beacon_interval =
4147                        get_unaligned_le16(&mgmt->u.beacon.beacon_int);
4148                bssid->tsf = get_unaligned_le64(&mgmt->u.beacon.timestamp);
4149        } else if (ieee80211_is_probe_req(mgmt->frame_control)) {
4150                length -= offsetof(struct ieee80211_mgmt, u.probe_req.variable);
4151                pie = mgmt->u.probe_req.variable;
4152                bssid->reserved = 2;
4153                bssid->capability = 0;
4154                bssid->beacon_interval =
4155                        padapter->registrypriv.dev_network.beacon_interval;
4156                bssid->tsf = 0;
4157        } else if (ieee80211_is_probe_resp(mgmt->frame_control)) {
4158                length -=
4159                        offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
4160                pie = mgmt->u.probe_resp.variable;
4161                bssid->reserved = 3;
4162                bssid->capability =
4163                        get_unaligned_le16(&mgmt->u.probe_resp.capab_info);
4164                bssid->beacon_interval =
4165                        get_unaligned_le16(&mgmt->u.probe_resp.beacon_int);
4166                bssid->tsf = get_unaligned_le64(&mgmt->u.probe_resp.timestamp);
4167        } else {
4168                length -= offsetof(struct ieee80211_mgmt, u.beacon.variable);
4169                pie = mgmt->u.beacon.variable;
4170                bssid->reserved = 0;
4171                bssid->capability =
4172                        get_unaligned_le16(&mgmt->u.beacon.capab_info);
4173                bssid->beacon_interval =
4174                        padapter->registrypriv.dev_network.beacon_interval;
4175                bssid->tsf = 0;
4176        }
4177
4178        if (length > MAX_IE_SZ) {
4179                /* DBG_8723A("IE too long for survey event\n"); */
4180                kfree(bssid);
4181                return NULL;
4182        }
4183
4184        bssid->Length = offsetof(struct wlan_bssid_ex, IEs) + length;
4185
4186        /* below is to copy the information element */
4187        bssid->IELength = length;
4188        memcpy(bssid->IEs, pie, bssid->IELength);
4189
4190        /* get the signal strength */
4191        /*  in dBM.raw data */
4192        bssid->Rssi = precv_frame->attrib.phy_info.RecvSignalPower;
4193        bssid->SignalQuality =
4194                precv_frame->attrib.phy_info.SignalQuality;/* in percentage */
4195        bssid->SignalStrength =
4196                precv_frame->attrib.phy_info.SignalStrength;/* in percentage */
4197
4198        /*  checking SSID */
4199        p = cfg80211_find_ie(WLAN_EID_SSID, bssid->IEs, bssid->IELength);
4200
4201        if (!p) {
4202                DBG_8723A("marc: cannot find SSID for survey event\n");
4203                goto fail;
4204        }
4205
4206        if (p[1] > IEEE80211_MAX_SSID_LEN) {
4207                DBG_8723A("%s()-%d: IE too long (%d) for survey "
4208                          "event\n", __func__, __LINE__, p[1]);
4209                goto fail;
4210        }
4211        memcpy(bssid->Ssid.ssid, p + 2, p[1]);
4212        bssid->Ssid.ssid_len = p[1];
4213
4214        /* checking rate info... */
4215        i = 0;
4216        p = cfg80211_find_ie(WLAN_EID_SUPP_RATES, bssid->IEs, bssid->IELength);
4217        if (p) {
4218                if (p[1] > NDIS_802_11_LENGTH_RATES_EX) {
4219                        DBG_8723A("%s()-%d: IE too long (%d) for survey "
4220                                  "event\n", __func__, __LINE__, p[1]);
4221                        goto fail;
4222                }
4223                memcpy(bssid->SupportedRates, p + 2, p[1]);
4224                i = p[1];
4225        }
4226
4227        p = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, bssid->IEs,
4228                             bssid->IELength);
4229        if (p) {
4230                if (p[1] > (NDIS_802_11_LENGTH_RATES_EX-i)) {
4231                        DBG_8723A("%s()-%d: IE too long (%d) for survey "
4232                                  "event\n", __func__, __LINE__, p[1]);
4233                        goto fail;
4234                }
4235                memcpy(bssid->SupportedRates + i, p + 2, p[1]);
4236        }
4237
4238        /*  Checking for DSConfig */
4239        p = cfg80211_find_ie(WLAN_EID_DS_PARAMS, bssid->IEs, bssid->IELength);
4240
4241        bssid->DSConfig = 0;
4242
4243        if (p) {
4244                bssid->DSConfig = p[2];
4245        } else {/*  In 5G, some ap do not have DSSET IE */
4246                /*  checking HT info for channel */
4247                p = cfg80211_find_ie(WLAN_EID_HT_OPERATION, bssid->IEs,
4248                                     bssid->IELength);
4249                if (p) {
4250                        struct ieee80211_ht_operation *HT_info =
4251                                (struct ieee80211_ht_operation *)(p + 2);
4252                        bssid->DSConfig = HT_info->primary_chan;
4253                } else /*  use current channel */
4254                        bssid->DSConfig = rtw_get_oper_ch23a(padapter);
4255        }
4256
4257        if (ieee80211_is_probe_req(mgmt->frame_control)) {
4258                /*  FIXME */
4259                bssid->ifmode = NL80211_IFTYPE_STATION;
4260                ether_addr_copy(bssid->MacAddress, mgmt->sa);
4261                bssid->Privacy = 1;
4262                return bssid;
4263        }
4264
4265        if (bssid->capability & WLAN_CAPABILITY_ESS) {
4266                bssid->ifmode = NL80211_IFTYPE_STATION;
4267                ether_addr_copy(bssid->MacAddress, mgmt->sa);
4268        } else {
4269                bssid->ifmode = NL80211_IFTYPE_ADHOC;
4270                ether_addr_copy(bssid->MacAddress, mgmt->bssid);
4271        }
4272
4273        if (bssid->capability & WLAN_CAPABILITY_PRIVACY)
4274                bssid->Privacy = 1;
4275        else
4276                bssid->Privacy = 0;
4277
4278        bssid->ATIMWindow = 0;
4279
4280        /* 20/40 BSS Coexistence check */
4281        if (pregistrypriv->wifi_spec == 1 &&
4282            pmlmeinfo->bwmode_updated == false) {
4283                struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
4284
4285                p = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, bssid->IEs,
4286                                     bssid->IELength);
4287                if (p && p[1] > 0) {
4288                        struct ieee80211_ht_cap *pHT_caps;
4289
4290                        pHT_caps = (struct ieee80211_ht_cap *)(p + 2);
4291
4292                        if (pHT_caps->cap_info &
4293                            cpu_to_le16(IEEE80211_HT_CAP_40MHZ_INTOLERANT))
4294                                pmlmepriv->num_FortyMHzIntolerant++;
4295                } else
4296                        pmlmepriv->num_sta_no_ht++;
4297        }
4298
4299
4300        /*  mark bss info receiving from nearby channel as SignalQuality 101 */
4301        if (bssid->DSConfig != rtw_get_oper_ch23a(padapter))
4302                bssid->SignalQuality = 101;
4303
4304        return bssid;
4305fail:
4306        kfree (bssid);
4307        return NULL;
4308}
4309
4310static void start_create_ibss(struct rtw_adapter *padapter)
4311{
4312        unsigned short caps;
4313        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
4314        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
4315        struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
4316
4317        pmlmeext->cur_channel = (u8)pnetwork->DSConfig;
4318        pmlmeinfo->bcn_interval = pnetwork->beacon_interval;
4319
4320        /* update wireless mode */
4321        update_wireless_mode23a(padapter);
4322
4323        /* update capability */
4324        caps = pnetwork->capability;
4325        update_capinfo23a(padapter, caps);
4326        if (caps & WLAN_CAPABILITY_IBSS) {      /* adhoc master */
4327                rtl8723a_set_sec_cfg(padapter, 0xcf);
4328
4329                /* switch channel */
4330                /* SelectChannel23a(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE); */
4331                set_channel_bwmode23a(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
4332
4333                rtl8723a_SetBeaconRelatedRegisters(padapter);
4334
4335                /* set msr to MSR_ADHOC */
4336                pmlmeinfo->state = MSR_ADHOC;
4337                rtl8723a_set_media_status(padapter, pmlmeinfo->state & 0x3);
4338
4339                /* issue beacon */
4340                if (send_beacon23a(padapter) == _FAIL) {
4341                        RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
4342                                 "issuing beacon frame fail....\n");
4343
4344                        report_join_res23a(padapter, -1);
4345                        pmlmeinfo->state = MSR_NOLINK;
4346                } else {
4347                        hw_var_set_bssid(padapter, padapter->registrypriv.dev_network.MacAddress);
4348                        hw_var_set_mlme_join(padapter, 0);
4349
4350                        report_join_res23a(padapter, 1);
4351                        pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS;
4352                }
4353        } else {
4354                DBG_8723A("%s: invalid cap:%x\n", __func__, caps);
4355                return;
4356        }
4357}
4358
4359static void start_clnt_join(struct rtw_adapter *padapter)
4360{
4361        unsigned short caps;
4362        u8 val8;
4363        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
4364        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
4365        struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
4366        int beacon_timeout;
4367
4368        pmlmeext->cur_channel = (u8)pnetwork->DSConfig;
4369        pmlmeinfo->bcn_interval = pnetwork->beacon_interval;
4370
4371        /* update wireless mode */
4372        update_wireless_mode23a(padapter);
4373
4374        /* update capability */
4375        caps = pnetwork->capability;
4376        update_capinfo23a(padapter, caps);
4377        if (caps & WLAN_CAPABILITY_ESS) {
4378                /* switch channel */
4379                set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
4380
4381                rtl8723a_set_media_status(padapter, MSR_INFRA);
4382
4383                val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X) ?
4384                        0xcc: 0xcf;
4385
4386                rtl8723a_set_sec_cfg(padapter, val8);
4387
4388                /* switch channel */
4389                /* set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */
4390
4391                /* here wait for receiving the beacon to start auth */
4392                /* and enable a timer */
4393                beacon_timeout = decide_wait_for_beacon_timeout23a(pmlmeinfo->bcn_interval);
4394                set_link_timer(pmlmeext, beacon_timeout);
4395                mod_timer(&padapter->mlmepriv.assoc_timer, jiffies +
4396                          msecs_to_jiffies((REAUTH_TO * REAUTH_LIMIT) + (REASSOC_TO*REASSOC_LIMIT) + beacon_timeout));
4397                pmlmeinfo->state = WIFI_FW_AUTH_NULL | MSR_INFRA;
4398        } else if (caps & WLAN_CAPABILITY_IBSS) {       /* adhoc client */
4399                rtl8723a_set_media_status(padapter, MSR_ADHOC);
4400
4401                rtl8723a_set_sec_cfg(padapter, 0xcf);
4402
4403                /* switch channel */
4404                set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
4405
4406                rtl8723a_SetBeaconRelatedRegisters(padapter);
4407
4408                pmlmeinfo->state = MSR_ADHOC;
4409
4410                report_join_res23a(padapter, 1);
4411        } else {
4412                /* DBG_8723A("marc: invalid cap:%x\n", caps); */
4413                return;
4414        }
4415}
4416
4417static void start_clnt_auth(struct rtw_adapter *padapter)
4418{
4419        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
4420        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
4421
4422        del_timer_sync(&pmlmeext->link_timer);
4423
4424        pmlmeinfo->state &= (~WIFI_FW_AUTH_NULL);
4425        pmlmeinfo->state |= WIFI_FW_AUTH_STATE;
4426
4427        pmlmeinfo->auth_seq = 1;
4428        pmlmeinfo->reauth_count = 0;
4429        pmlmeinfo->reassoc_count = 0;
4430        pmlmeinfo->link_count = 0;
4431        pmlmeext->retry = 0;
4432
4433        /*  Because of AP's not receiving deauth before */
4434        /*  AP may: 1)not response auth or 2)deauth us after link is complete */
4435        /*  issue deauth before issuing auth to deal with the situation */
4436        /*      Commented by Albert 2012/07/21 */
4437        /*      For the Win8 P2P connection, it will be hard to have a
4438                successful connection if this Wi-Fi doesn't connect to it. */
4439        issue_deauth23a(padapter, (&pmlmeinfo->network)->MacAddress,
4440                        WLAN_REASON_DEAUTH_LEAVING);
4441
4442        DBG_8723A_LEVEL(_drv_always_, "start auth\n");
4443        issue_auth(padapter, NULL, 0);
4444
4445        set_link_timer(pmlmeext, REAUTH_TO);
4446}
4447
4448static void start_clnt_assoc(struct rtw_adapter *padapter)
4449{
4450        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
4451        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
4452
4453        del_timer_sync(&pmlmeext->link_timer);
4454
4455        pmlmeinfo->state &= (~(WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE));
4456        pmlmeinfo->state |= (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE);
4457
4458        issue_assocreq(padapter);
4459
4460        set_link_timer(pmlmeext, REASSOC_TO);
4461}
4462
4463int receive_disconnect23a(struct rtw_adapter *padapter,
4464                          unsigned char *MacAddr, unsigned short reason)
4465{
4466        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
4467        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
4468
4469        /* check A3 */
4470        if (!ether_addr_equal(MacAddr, get_my_bssid23a(&pmlmeinfo->network)))
4471                return _SUCCESS;
4472
4473        DBG_8723A("%s\n", __func__);
4474
4475        if ((pmlmeinfo->state&0x03) == MSR_INFRA) {
4476                if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) {
4477                        pmlmeinfo->state = MSR_NOLINK;
4478                        report_del_sta_event23a(padapter, MacAddr, reason);
4479
4480                } else if (pmlmeinfo->state & WIFI_FW_LINKING_STATE) {
4481                        pmlmeinfo->state = MSR_NOLINK;
4482                        report_join_res23a(padapter, -2);
4483                }
4484        }
4485
4486        return _SUCCESS;
4487}
4488
4489static void process_80211d(struct rtw_adapter *padapter,
4490                           struct wlan_bssid_ex *bssid)
4491{
4492        struct registry_priv *pregistrypriv;
4493        struct mlme_ext_priv *pmlmeext;
4494        struct rt_channel_info *chplan_new;
4495        u8 channel;
4496        u8 i;
4497
4498        pregistrypriv = &padapter->registrypriv;
4499        pmlmeext = &padapter->mlmeextpriv;
4500
4501        /*  Adjust channel plan by AP Country IE */
4502        if (pregistrypriv->enable80211d &&
4503            !pmlmeext->update_channel_plan_by_ap_done) {
4504                const u8 *ie, *p;
4505                struct rt_channel_plan chplan_ap;
4506                struct rt_channel_info chplan_sta[MAX_CHANNEL_NUM];
4507                u8 country[4];
4508                u8 fcn; /*  first channel number */
4509                u8 noc; /*  number of channel */
4510                u8 j, k;
4511
4512                ie = cfg80211_find_ie(WLAN_EID_COUNTRY, bssid->IEs,
4513                                      bssid->IELength);
4514                if (!ie || ie[1] < IEEE80211_COUNTRY_IE_MIN_LEN)
4515                        return;
4516
4517                p = ie + 2;
4518                ie += ie[1];
4519                ie += 2;
4520
4521                memcpy(country, p, 3);
4522                country[3] = '\0';
4523
4524                p += 3;
4525                RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
4526                         "%s: 802.11d country =%s\n", __func__, country);
4527
4528                i = 0;
4529                while ((ie - p) >= 3) {
4530                        fcn = *(p++);
4531                        noc = *(p++);
4532                        p++;
4533
4534                        for (j = 0; j < noc; j++) {
4535                                if (fcn <= 14)
4536                                        channel = fcn + j; /*  2.4 GHz */
4537                                else
4538                                        channel = fcn + j * 4; /*  5 GHz */
4539
4540                                chplan_ap.Channel[i++] = channel;
4541                        }
4542                }
4543                chplan_ap.Len = i;
4544
4545                memcpy(chplan_sta, pmlmeext->channel_set, sizeof(chplan_sta));
4546                memset(pmlmeext->channel_set, 0, sizeof(pmlmeext->channel_set));
4547                chplan_new = pmlmeext->channel_set;
4548
4549                i = j = k = 0;
4550                if (pregistrypriv->wireless_mode & WIRELESS_11G) {
4551                        do {
4552                                if (i == MAX_CHANNEL_NUM ||
4553                                    chplan_sta[i].ChannelNum == 0 ||
4554                                    chplan_sta[i].ChannelNum > 14)
4555                                        break;
4556
4557                                if (j == chplan_ap.Len ||
4558                                    chplan_ap.Channel[j] > 14)
4559                                        break;
4560
4561                                if (chplan_sta[i].ChannelNum ==
4562                                    chplan_ap.Channel[j]) {
4563                                        chplan_new[k].ChannelNum =
4564                                                chplan_ap.Channel[j];
4565                                        chplan_new[k].ScanType = SCAN_ACTIVE;
4566                                        i++;
4567                                        j++;
4568                                        k++;
4569                                } else if (chplan_sta[i].ChannelNum <
4570                                           chplan_ap.Channel[j]) {
4571                                        chplan_new[k].ChannelNum =
4572                                                chplan_sta[i].ChannelNum;
4573                                        chplan_new[k].ScanType =
4574                                                SCAN_PASSIVE;
4575                                        i++;
4576                                        k++;
4577                                } else if (chplan_sta[i].ChannelNum >
4578                                           chplan_ap.Channel[j]) {
4579                                        chplan_new[k].ChannelNum =
4580                                                chplan_ap.Channel[j];
4581                                        chplan_new[k].ScanType =
4582                                                SCAN_ACTIVE;
4583                                        j++;
4584                                        k++;
4585                                }
4586                        } while (1);
4587
4588                        /*  change AP not support channel to Passive scan */
4589                        while (i < MAX_CHANNEL_NUM &&
4590                               chplan_sta[i].ChannelNum != 0 &&
4591                               chplan_sta[i].ChannelNum <= 14) {
4592                                chplan_new[k].ChannelNum =
4593                                        chplan_sta[i].ChannelNum;
4594                                chplan_new[k].ScanType = SCAN_PASSIVE;
4595                                i++;
4596                                k++;
4597                        }
4598
4599                        /*  add channel AP supported */
4600                        while (j < chplan_ap.Len && chplan_ap.Channel[j] <= 14){
4601                                chplan_new[k].ChannelNum = chplan_ap.Channel[j];
4602                                chplan_new[k].ScanType = SCAN_ACTIVE;
4603                                j++;
4604                                k++;
4605                        }
4606                } else {
4607                        /*  keep original STA 2.4G channel plan */
4608                        while (i < MAX_CHANNEL_NUM &&
4609                               chplan_sta[i].ChannelNum != 0 &&
4610                               chplan_sta[i].ChannelNum <= 14) {
4611                                chplan_new[k].ChannelNum =
4612                                        chplan_sta[i].ChannelNum;
4613                                chplan_new[k].ScanType = chplan_sta[i].ScanType;
4614                                i++;
4615                                k++;
4616                        }
4617
4618                        /*  skip AP 2.4G channel plan */
4619                        while (j < chplan_ap.Len && chplan_ap.Channel[j] <= 14)
4620                                j++;
4621                }
4622
4623                if (pregistrypriv->wireless_mode & WIRELESS_11A) {
4624                        do {
4625                                if (i == MAX_CHANNEL_NUM ||
4626                                    chplan_sta[i].ChannelNum == 0)
4627                                        break;
4628
4629                                if (j == chplan_ap.Len ||
4630                                    chplan_ap.Channel[j] == 0)
4631                                        break;
4632
4633                                if (chplan_sta[i].ChannelNum ==
4634                                    chplan_ap.Channel[j]) {
4635                                        chplan_new[k].ChannelNum =
4636                                                chplan_ap.Channel[j];
4637                                        chplan_new[k].ScanType = SCAN_ACTIVE;
4638                                        i++;
4639                                        j++;
4640                                        k++;
4641                                } else if (chplan_sta[i].ChannelNum <
4642                                           chplan_ap.Channel[j]) {
4643                                        chplan_new[k].ChannelNum =
4644                                                chplan_sta[i].ChannelNum;
4645                                        chplan_new[k].ScanType = SCAN_PASSIVE;
4646                                        i++;
4647                                        k++;
4648                                } else if (chplan_sta[i].ChannelNum >
4649                                           chplan_ap.Channel[j]) {
4650                                        chplan_new[k].ChannelNum =
4651                                                chplan_ap.Channel[j];
4652                                        chplan_new[k].ScanType = SCAN_ACTIVE;
4653                                        j++;
4654                                        k++;
4655                                }
4656                        } while (1);
4657
4658                        /*  change AP not support channel to Passive scan */
4659                        while (i < MAX_CHANNEL_NUM &&
4660                               chplan_sta[i].ChannelNum != 0) {
4661                                chplan_new[k].ChannelNum =
4662                                        chplan_sta[i].ChannelNum;
4663                                chplan_new[k].ScanType = SCAN_PASSIVE;
4664                                i++;
4665                                k++;
4666                        }
4667
4668                        /*  add channel AP supported */
4669                        while (j < chplan_ap.Len && chplan_ap.Channel[j] != 0) {
4670                                chplan_new[k].ChannelNum = chplan_ap.Channel[j];
4671                                chplan_new[k].ScanType = SCAN_ACTIVE;
4672                                j++;
4673                                k++;
4674                        }
4675                } else {
4676                        /*  keep original STA 5G channel plan */
4677                        while (i < MAX_CHANNEL_NUM &&
4678                               chplan_sta[i].ChannelNum != 0) {
4679                                chplan_new[k].ChannelNum =
4680                                        chplan_sta[i].ChannelNum;
4681                                chplan_new[k].ScanType = chplan_sta[i].ScanType;
4682                                i++;
4683                                k++;
4684                        }
4685                }
4686                pmlmeext->update_channel_plan_by_ap_done = 1;
4687        }
4688
4689        /*  If channel is used by AP, set channel scan type to active */
4690        channel = bssid->DSConfig;
4691        chplan_new = pmlmeext->channel_set;
4692        i = 0;
4693        while (i < MAX_CHANNEL_NUM && chplan_new[i].ChannelNum != 0) {
4694                if (chplan_new[i].ChannelNum == channel) {
4695                        if (chplan_new[i].ScanType == SCAN_PASSIVE) {
4696                                /* 5G Bnad 2, 3 (DFS) doesn't change
4697                                   to active scan */
4698                                if (channel >= 52 && channel <= 144)
4699                                        break;
4700
4701                                chplan_new[i].ScanType = SCAN_ACTIVE;
4702                                RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
4703                                         "%s: change channel %d scan type from passive to active\n",
4704                                         __func__, channel);
4705                        }
4706                        break;
4707                }
4708                i++;
4709        }
4710}
4711
4712/****************************************************************************
4713
4714Following are the functions to report events
4715
4716*****************************************************************************/
4717
4718void report_survey_event23a(struct rtw_adapter *padapter,
4719                            struct recv_frame *precv_frame)
4720{
4721        struct cmd_obj *pcmd_obj;
4722        u8 *pevtcmd;
4723        u32 cmdsz;
4724        struct survey_event *psurvey_evt;
4725        struct C2HEvent_Header *pc2h_evt_hdr;
4726        struct mlme_ext_priv *pmlmeext;
4727        struct cmd_priv *pcmdpriv;
4728
4729        if (!padapter)
4730                return;
4731
4732        pmlmeext = &padapter->mlmeextpriv;
4733        pcmdpriv = &padapter->cmdpriv;
4734
4735        pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
4736        if (!pcmd_obj)
4737                return;
4738
4739        cmdsz = sizeof(struct survey_event) + sizeof(struct C2HEvent_Header);
4740        pevtcmd = kzalloc(cmdsz, GFP_ATOMIC);
4741        if (!pevtcmd) {
4742                kfree(pcmd_obj);
4743                return;
4744        }
4745
4746        pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
4747        pcmd_obj->cmdsz = cmdsz;
4748        pcmd_obj->parmbuf = pevtcmd;
4749
4750        pcmd_obj->rsp = NULL;
4751        pcmd_obj->rspsz  = 0;
4752
4753        pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
4754        pc2h_evt_hdr->len = sizeof(struct survey_event);
4755        pc2h_evt_hdr->ID = GEN_EVT_CODE(_Survey);
4756        pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq);
4757
4758        psurvey_evt = (struct survey_event*)(pevtcmd + sizeof(struct C2HEvent_Header));
4759
4760        psurvey_evt->bss = collect_bss_info(padapter, precv_frame);
4761        if (!psurvey_evt->bss) {
4762                kfree(pcmd_obj);
4763                kfree(pevtcmd);
4764                return;
4765        }
4766
4767        process_80211d(padapter, psurvey_evt->bss);
4768
4769        rtw_enqueue_cmd23a(pcmdpriv, pcmd_obj);
4770
4771        pmlmeext->sitesurvey_res.bss_cnt++;
4772
4773        return;
4774}
4775
4776void report_surveydone_event23a(struct rtw_adapter *padapter)
4777{
4778        struct cmd_obj *pcmd_obj;
4779        u8 *pevtcmd;
4780        u32 cmdsz;
4781        struct surveydone_event *psurveydone_evt;
4782        struct C2HEvent_Header *pc2h_evt_hdr;
4783        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
4784        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
4785
4786        pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
4787        if (!pcmd_obj)
4788                return;
4789
4790        cmdsz = sizeof(struct surveydone_event) + sizeof(struct C2HEvent_Header);
4791        pevtcmd = kzalloc(cmdsz, GFP_ATOMIC);
4792        if (!pevtcmd) {
4793                kfree(pcmd_obj);
4794                return;
4795        }
4796
4797        pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
4798        pcmd_obj->cmdsz = cmdsz;
4799        pcmd_obj->parmbuf = pevtcmd;
4800
4801        pcmd_obj->rsp = NULL;
4802        pcmd_obj->rspsz  = 0;
4803
4804        pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
4805        pc2h_evt_hdr->len = sizeof(struct surveydone_event);
4806        pc2h_evt_hdr->ID = GEN_EVT_CODE(_SurveyDone);
4807        pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq);
4808
4809        psurveydone_evt = (struct surveydone_event*)(pevtcmd + sizeof(struct C2HEvent_Header));
4810        psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt;
4811
4812        DBG_8723A("survey done event(%x)\n", psurveydone_evt->bss_cnt);
4813
4814        rtw_enqueue_cmd23a(pcmdpriv, pcmd_obj);
4815
4816        return;
4817}
4818
4819void report_join_res23a(struct rtw_adapter *padapter, int res)
4820{
4821        struct cmd_obj *pcmd_obj;
4822        u8 *pevtcmd;
4823        u32 cmdsz;
4824        struct joinbss_event            *pjoinbss_evt;
4825        struct C2HEvent_Header  *pc2h_evt_hdr;
4826        struct mlme_ext_priv            *pmlmeext = &padapter->mlmeextpriv;
4827        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
4828        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
4829
4830        pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
4831        if (!pcmd_obj)
4832                return;
4833
4834        cmdsz = sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header);
4835        pevtcmd = kzalloc(cmdsz, GFP_ATOMIC);
4836        if (!pevtcmd) {
4837                kfree(pcmd_obj);
4838                return;
4839        }
4840
4841        pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
4842        pcmd_obj->cmdsz = cmdsz;
4843        pcmd_obj->parmbuf = pevtcmd;
4844
4845        pcmd_obj->rsp = NULL;
4846        pcmd_obj->rspsz  = 0;
4847
4848        pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
4849        pc2h_evt_hdr->len = sizeof(struct joinbss_event);
4850        pc2h_evt_hdr->ID = GEN_EVT_CODE(_JoinBss);
4851        pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq);
4852
4853        pjoinbss_evt = (struct joinbss_event*)(pevtcmd + sizeof(struct C2HEvent_Header));
4854        memcpy((unsigned char *)&pjoinbss_evt->network.network,
4855               &pmlmeinfo->network, sizeof(struct wlan_bssid_ex));
4856        pjoinbss_evt->network.join_res = res;
4857
4858        DBG_8723A("report_join_res23a(%d)\n", res);
4859
4860        rtw_joinbss_event_prehandle23a(padapter, (u8 *)&pjoinbss_evt->network);
4861
4862        rtw_enqueue_cmd23a(pcmdpriv, pcmd_obj);
4863
4864        return;
4865}
4866
4867void report_del_sta_event23a(struct rtw_adapter *padapter,
4868                             unsigned char *MacAddr, unsigned short reason)
4869{
4870        struct cmd_obj *pcmd_obj;
4871        u8 *pevtcmd;
4872        u32 cmdsz;
4873        struct sta_info *psta;
4874        int mac_id;
4875        struct stadel_event *pdel_sta_evt;
4876        struct C2HEvent_Header *pc2h_evt_hdr;
4877        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
4878        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
4879
4880        pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
4881        if (!pcmd_obj)
4882                return;
4883
4884        cmdsz = sizeof(struct stadel_event) + sizeof(struct C2HEvent_Header);
4885        pevtcmd = kzalloc(cmdsz, GFP_ATOMIC);
4886        if (!pevtcmd) {
4887                kfree(pcmd_obj);
4888                return;
4889        }
4890
4891        pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
4892        pcmd_obj->cmdsz = cmdsz;
4893        pcmd_obj->parmbuf = pevtcmd;
4894
4895        pcmd_obj->rsp = NULL;
4896        pcmd_obj->rspsz  = 0;
4897
4898        pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
4899        pc2h_evt_hdr->len = sizeof(struct stadel_event);
4900        pc2h_evt_hdr->ID = GEN_EVT_CODE(_DelSTA);
4901        pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq);
4902
4903        pdel_sta_evt = (struct stadel_event*)(pevtcmd + sizeof(struct C2HEvent_Header));
4904        ether_addr_copy((unsigned char *)&pdel_sta_evt->macaddr, MacAddr);
4905        memcpy((unsigned char *)pdel_sta_evt->rsvd, (unsigned char *)&reason,
4906               2);
4907
4908        psta = rtw_get_stainfo23a(&padapter->stapriv, MacAddr);
4909        if (psta)
4910                mac_id = (int)psta->mac_id;
4911        else
4912                mac_id = -1;
4913
4914        pdel_sta_evt->mac_id = mac_id;
4915
4916        DBG_8723A("report_del_sta_event23a: delete STA, mac_id =%d\n", mac_id);
4917
4918        rtw_enqueue_cmd23a(pcmdpriv, pcmd_obj);
4919
4920        return;
4921}
4922
4923void report_add_sta_event23a(struct rtw_adapter *padapter,
4924                             unsigned char *MacAddr, int cam_idx)
4925{
4926        struct cmd_obj *pcmd_obj;
4927        u8 *pevtcmd;
4928        u32 cmdsz;
4929        struct stassoc_event *padd_sta_evt;
4930        struct C2HEvent_Header *pc2h_evt_hdr;
4931        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
4932        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
4933
4934        pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
4935        if (!pcmd_obj)
4936                return;
4937
4938        cmdsz = sizeof(struct stassoc_event) + sizeof(struct C2HEvent_Header);
4939        pevtcmd = kzalloc(cmdsz, GFP_ATOMIC);
4940        if (!pevtcmd) {
4941                kfree(pcmd_obj);
4942                return;
4943        }
4944
4945        pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
4946        pcmd_obj->cmdsz = cmdsz;
4947        pcmd_obj->parmbuf = pevtcmd;
4948
4949        pcmd_obj->rsp = NULL;
4950        pcmd_obj->rspsz  = 0;
4951
4952        pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
4953        pc2h_evt_hdr->len = sizeof(struct stassoc_event);
4954        pc2h_evt_hdr->ID = GEN_EVT_CODE(_AddSTA);
4955        pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq);
4956
4957        padd_sta_evt = (struct stassoc_event*)(pevtcmd + sizeof(struct C2HEvent_Header));
4958        ether_addr_copy((unsigned char *)&padd_sta_evt->macaddr, MacAddr);
4959        padd_sta_evt->cam_id = cam_idx;
4960
4961        DBG_8723A("report_add_sta_event23a: add STA\n");
4962
4963        rtw_enqueue_cmd23a(pcmdpriv, pcmd_obj);
4964
4965        return;
4966}
4967
4968/****************************************************************************
4969
4970Following are the event callback functions
4971
4972*****************************************************************************/
4973
4974/* for sta/adhoc mode */
4975void update_sta_info23a(struct rtw_adapter *padapter, struct sta_info *psta)
4976{
4977        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
4978        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
4979        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
4980
4981        /* ERP */
4982        VCS_update23a(padapter, psta);
4983
4984        /* HT */
4985        if (pmlmepriv->htpriv.ht_option) {
4986                psta->htpriv.ht_option = true;
4987
4988                psta->htpriv.ampdu_enable = pmlmepriv->htpriv.ampdu_enable;
4989
4990                if (support_short_GI23a(padapter, &pmlmeinfo->ht_cap))
4991                        psta->htpriv.sgi = true;
4992
4993                psta->qos_option = true;
4994
4995        } else {
4996                psta->htpriv.ht_option = false;
4997
4998                psta->htpriv.ampdu_enable = false;
4999
5000                psta->htpriv.sgi = false;
5001                psta->qos_option = false;
5002
5003        }
5004        psta->htpriv.bwmode = pmlmeext->cur_bwmode;
5005        psta->htpriv.ch_offset = pmlmeext->cur_ch_offset;
5006
5007        psta->htpriv.agg_enable_bitmap = 0x0;/* reset */
5008        psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */
5009
5010        /* QoS */
5011        if (pmlmepriv->qos_option)
5012                psta->qos_option = true;
5013
5014        psta->state = _FW_LINKED;
5015}
5016
5017void mlmeext_joinbss_event_callback23a(struct rtw_adapter *padapter,
5018                                       int join_res)
5019{
5020        struct sta_info *psta, *psta_bmc;
5021        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5022        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
5023        struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
5024        struct sta_priv *pstapriv = &padapter->stapriv;
5025
5026        if (join_res < 0) {
5027                hw_var_set_mlme_join(padapter, 1);
5028                hw_var_set_bssid(padapter, null_addr);
5029
5030                /* restore to initial setting. */
5031                update_tx_basic_rate23a(padapter,
5032                                        padapter->registrypriv.wireless_mode);
5033
5034                goto exit_mlmeext_joinbss_event_callback23a;
5035        }
5036
5037        if ((pmlmeinfo->state&0x03) == MSR_ADHOC) {
5038                /* for bc/mc */
5039                psta_bmc = rtw_get_bcmc_stainfo23a(padapter);
5040                if (psta_bmc) {
5041                        pmlmeinfo->FW_sta_info[psta_bmc->mac_id].psta = psta_bmc;
5042                        update_bmc_sta_support_rate23a(padapter, psta_bmc->mac_id);
5043                        Update_RA_Entry23a(padapter, psta_bmc);
5044                }
5045        }
5046
5047        /* turn on dynamic functions */
5048        rtl8723a_odm_support_ability_set(padapter, DYNAMIC_ALL_FUNC_ENABLE);
5049
5050        /*  update IOT-releated issue */
5051        update_IOT_info23a(padapter);
5052
5053        HalSetBrateCfg23a(padapter, cur_network->SupportedRates);
5054
5055        /* BCN interval */
5056        rtl8723a_set_beacon_interval(padapter, pmlmeinfo->bcn_interval);
5057
5058        /* update capability */
5059        update_capinfo23a(padapter, pmlmeinfo->capability);
5060
5061        /* WMM, Update EDCA param */
5062        WMMOnAssocRsp23a(padapter);
5063
5064        /* HT */
5065        HTOnAssocRsp23a(padapter);
5066
5067        /* Set cur_channel&cur_bwmode&cur_ch_offset */
5068        set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
5069
5070        psta = rtw_get_stainfo23a(pstapriv, cur_network->MacAddress);
5071        if (psta) { /* only for infra. mode */
5072                pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta;
5073
5074                /* DBG_8723A("set_sta_rate23a\n"); */
5075
5076                psta->wireless_mode = pmlmeext->cur_wireless_mode;
5077
5078                /* set per sta rate after updating HT cap. */
5079                set_sta_rate23a(padapter, psta);
5080        }
5081
5082        hw_var_set_mlme_join(padapter, 2);
5083
5084        if ((pmlmeinfo->state&0x03) == MSR_INFRA) {
5085                /*  correcting TSF */
5086                rtw_correct_TSF(padapter);
5087
5088                /* set_link_timer(pmlmeext, DISCONNECT_TO); */
5089        }
5090
5091        rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_CONNECT, 0);
5092
5093exit_mlmeext_joinbss_event_callback23a:
5094        DBG_8723A("=>%s\n", __func__);
5095}
5096
5097void mlmeext_sta_add_event_callback23a(struct rtw_adapter *padapter,
5098                                       struct sta_info *psta)
5099{
5100        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5101        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
5102
5103        DBG_8723A("%s\n", __func__);
5104
5105        if ((pmlmeinfo->state & 0x03) == MSR_ADHOC) {
5106        /* adhoc master or sta_count>1 */
5107                if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) {
5108                        /* nothing to do */
5109                } else { /* adhoc client */
5110                        /*  correcting TSF */
5111                        rtw_correct_TSF(padapter);
5112
5113                        /* start beacon */
5114                        if (send_beacon23a(padapter) != _SUCCESS) {
5115                                pmlmeinfo->FW_sta_info[psta->mac_id].status = 0;
5116
5117                                pmlmeinfo->state ^= MSR_ADHOC;
5118
5119                                return;
5120                        }
5121
5122                        pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS;
5123                }
5124                hw_var_set_mlme_join(padapter, 2);
5125        }
5126
5127        pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta;
5128
5129        /* rate radaptive */
5130        Update_RA_Entry23a(padapter, psta);
5131
5132        /* update adhoc sta_info */
5133        update_sta_info23a(padapter, psta);
5134}
5135
5136void mlmeext_sta_del_event_callback23a(struct rtw_adapter *padapter)
5137{
5138        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5139        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
5140
5141        if (is_client_associated_to_ap23a(padapter) ||
5142            is_IBSS_empty23a(padapter)) {
5143                /* set_opmode_cmd(padapter, infra_client_with_mlme); */
5144
5145                hw_var_set_mlme_disconnect(padapter);
5146                hw_var_set_bssid(padapter, null_addr);
5147
5148                /* restore to initial setting. */
5149                update_tx_basic_rate23a(padapter,
5150                                        padapter->registrypriv.wireless_mode);
5151
5152                /* switch to the 20M Hz mode after disconnect */
5153                pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
5154                pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
5155
5156                set_channel_bwmode23a(padapter, pmlmeext->cur_channel,
5157                                      pmlmeext->cur_ch_offset,
5158                                      pmlmeext->cur_bwmode);
5159
5160                flush_all_cam_entry23a(padapter);
5161
5162                pmlmeinfo->state = MSR_NOLINK;
5163
5164                /* set MSR to no link state -> infra. mode */
5165                rtl8723a_set_media_status(padapter, MSR_INFRA);
5166
5167                del_timer_sync(&pmlmeext->link_timer);
5168        }
5169}
5170
5171static u8 chk_ap_is_alive(struct rtw_adapter *padapter, struct sta_info *psta)
5172{
5173        u8 ret = false;
5174
5175        if (sta_rx_data_pkts(psta) == sta_last_rx_data_pkts(psta) &&
5176            sta_rx_beacon_pkts(psta) == sta_last_rx_beacon_pkts(psta) &&
5177            sta_rx_probersp_pkts(psta) == sta_last_rx_probersp_pkts(psta))
5178                ret = false;
5179        else
5180                ret = true;
5181
5182        sta_update_last_rx_pkts(psta);
5183        return ret;
5184}
5185
5186void linked_status_chk23a(struct rtw_adapter *padapter)
5187{
5188        u32 i;
5189        struct sta_info *psta;
5190        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
5191        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5192        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
5193        struct sta_priv *pstapriv = &padapter->stapriv;
5194
5195        if (is_client_associated_to_ap23a(padapter)) {
5196                /* linked infrastructure client mode */
5197
5198                int tx_chk = _SUCCESS, rx_chk = _SUCCESS;
5199                int rx_chk_limit;
5200
5201                rx_chk_limit = 4;
5202
5203                psta = rtw_get_stainfo23a(pstapriv,
5204                                          pmlmeinfo->network.MacAddress);
5205                if (psta) {
5206                        bool is_p2p_enable = false;
5207
5208                        if (chk_ap_is_alive(padapter, psta) == false)
5209                                rx_chk = _FAIL;
5210
5211                        if (pxmitpriv->last_tx_pkts == pxmitpriv->tx_pkts)
5212                                tx_chk = _FAIL;
5213
5214                        if (pmlmeext->active_keep_alive_check &&
5215                            (rx_chk == _FAIL || tx_chk == _FAIL)) {
5216                                u8 backup_oper_channel = 0;
5217
5218                                /* switch to correct channel of current
5219                                   network  before issue keep-alive frames */
5220                                if (rtw_get_oper_ch23a(padapter) !=
5221                                    pmlmeext->cur_channel) {
5222                                        backup_oper_channel =
5223                                                rtw_get_oper_ch23a(padapter);
5224                                        SelectChannel23a(padapter,
5225                                                         pmlmeext->cur_channel);
5226                                }
5227
5228                                if (rx_chk != _SUCCESS)
5229                                        issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, psta->hwaddr, 3, 1);
5230
5231                                if ((tx_chk != _SUCCESS &&
5232                                     pmlmeinfo->link_count++ == 0xf) ||
5233                                    rx_chk != _SUCCESS) {
5234                                        tx_chk = issue_nulldata23a(padapter,
5235                                                                   psta->hwaddr,
5236                                                                   0, 3, 1);
5237                                        /* if tx acked and p2p disabled,
5238                                           set rx_chk _SUCCESS to reset retry
5239                                           count */
5240                                        if (tx_chk == _SUCCESS &&
5241                                            !is_p2p_enable)
5242                                                rx_chk = _SUCCESS;
5243                                }
5244
5245                                /* back to the original operation channel */
5246                                if (backup_oper_channel>0)
5247                                        SelectChannel23a(padapter,
5248                                                         backup_oper_channel);
5249                        } else {
5250                                if (rx_chk != _SUCCESS) {
5251                                        if (pmlmeext->retry == 0) {
5252                                                issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress);
5253                                                issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress);
5254                                                issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress);
5255                                        }
5256                                }
5257
5258                                if (tx_chk != _SUCCESS &&
5259                                    pmlmeinfo->link_count++ == 0xf)
5260                                        tx_chk = issue_nulldata23a(padapter,
5261                                                                   NULL, 0, 1,
5262                                                                   0);
5263                        }
5264
5265                        if (rx_chk == _FAIL) {
5266                                pmlmeext->retry++;
5267                                if (pmlmeext->retry > rx_chk_limit) {
5268                                        DBG_8723A_LEVEL(_drv_always_,
5269                                                        "%s(%s): disconnect or "
5270                                                        "roaming\n", __func__,
5271                                                        padapter->pnetdev->name);
5272                                        receive_disconnect23a(padapter, pmlmeinfo->network.MacAddress,
5273                                                WLAN_REASON_EXPIRATION_CHK);
5274                                        return;
5275                                }
5276                        } else
5277                                pmlmeext->retry = 0;
5278
5279                        if (tx_chk == _FAIL)
5280                                pmlmeinfo->link_count &= 0xf;
5281                        else {
5282                                pxmitpriv->last_tx_pkts = pxmitpriv->tx_pkts;
5283                                pmlmeinfo->link_count = 0;
5284                        }
5285
5286                }
5287        } else if (is_client_associated_to_ibss23a(padapter)) {
5288                /* linked IBSS mode */
5289                /* for each assoc list entry to check the rx pkt counter */
5290                for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) {
5291                        if (pmlmeinfo->FW_sta_info[i].status == 1) {
5292                                psta = pmlmeinfo->FW_sta_info[i].psta;
5293
5294                                if (!psta)
5295                                        continue;
5296
5297                                if (pmlmeinfo->FW_sta_info[i].rx_pkt ==
5298                                    sta_rx_pkts(psta)) {
5299
5300                                        if (pmlmeinfo->FW_sta_info[i].retry<3) {
5301                                                pmlmeinfo->FW_sta_info[i].retry++;
5302                                        } else {
5303                                                pmlmeinfo->FW_sta_info[i].retry = 0;
5304                                                pmlmeinfo->FW_sta_info[i].status = 0;
5305                                                report_del_sta_event23a(padapter, psta->hwaddr,
5306                                                        65535/*  indicate disconnect caused by no rx */
5307                                                );
5308                                        }
5309                                } else {
5310                                        pmlmeinfo->FW_sta_info[i].retry = 0;
5311                                        pmlmeinfo->FW_sta_info[i].rx_pkt = (u32)sta_rx_pkts(psta);
5312                                }
5313                        }
5314                }
5315                /* set_link_timer(pmlmeext, DISCONNECT_TO); */
5316        }
5317}
5318
5319static void survey_timer_hdl(unsigned long data)
5320{
5321        struct rtw_adapter *padapter = (struct rtw_adapter *)data;
5322        struct cmd_obj *ph2c;
5323        struct sitesurvey_parm *psurveyPara;
5324        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
5325        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5326
5327        /* issue rtw_sitesurvey_cmd23a */
5328        if (pmlmeext->sitesurvey_res.state > SCAN_START) {
5329                if (pmlmeext->sitesurvey_res.state ==  SCAN_PROCESS)
5330                        pmlmeext->sitesurvey_res.channel_idx++;
5331
5332                if (pmlmeext->scan_abort == true) {
5333                        pmlmeext->sitesurvey_res.channel_idx =
5334                                pmlmeext->sitesurvey_res.ch_num;
5335                        DBG_8723A("%s idx:%d\n", __func__,
5336                                  pmlmeext->sitesurvey_res.channel_idx);
5337
5338                        pmlmeext->scan_abort = false;/* reset */
5339                }
5340
5341                ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
5342                if (!ph2c)
5343                        goto exit_survey_timer_hdl;
5344
5345                psurveyPara = kzalloc(sizeof(struct sitesurvey_parm),
5346                                        GFP_ATOMIC);
5347                if (!psurveyPara) {
5348                        kfree(ph2c);
5349                        goto exit_survey_timer_hdl;
5350                }
5351
5352                init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara,
5353                                           GEN_CMD_CODE(_SiteSurvey));
5354                rtw_enqueue_cmd23a(pcmdpriv, ph2c);
5355        }
5356
5357exit_survey_timer_hdl:
5358        return;
5359}
5360
5361static void link_timer_hdl(unsigned long data)
5362{
5363        struct rtw_adapter *padapter = (struct rtw_adapter *)data;
5364        /* static unsigned int          rx_pkt = 0; */
5365        /* static u64                           tx_cnt = 0; */
5366        /* struct xmit_priv *pxmitpriv = &padapter->xmitpriv; */
5367        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5368        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
5369        /* struct sta_priv              *pstapriv = &padapter->stapriv; */
5370
5371        if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) {
5372                DBG_8723A("link_timer_hdl:no beacon while connecting\n");
5373                pmlmeinfo->state = MSR_NOLINK;
5374                report_join_res23a(padapter, -3);
5375        } else if (pmlmeinfo->state & WIFI_FW_AUTH_STATE) {
5376                /* re-auth timer */
5377                if (++pmlmeinfo->reauth_count > REAUTH_LIMIT) {
5378                        /* if (pmlmeinfo->auth_algo != dot11AuthAlgrthm_Auto) */
5379                        /*  */
5380                                pmlmeinfo->state = 0;
5381                                report_join_res23a(padapter, -1);
5382                                return;
5383                        /*  */
5384                        /* else */
5385                        /*  */
5386                        /* pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; */
5387                        /* pmlmeinfo->reauth_count = 0; */
5388                        /*  */
5389                }
5390
5391                DBG_8723A("link_timer_hdl: auth timeout and try again\n");
5392                pmlmeinfo->auth_seq = 1;
5393                issue_auth(padapter, NULL, 0);
5394                set_link_timer(pmlmeext, REAUTH_TO);
5395        } else if (pmlmeinfo->state & WIFI_FW_ASSOC_STATE) {
5396                /* re-assoc timer */
5397                if (++pmlmeinfo->reassoc_count > REASSOC_LIMIT) {
5398                        pmlmeinfo->state = MSR_NOLINK;
5399                        report_join_res23a(padapter, -2);
5400                        return;
5401                }
5402
5403                DBG_8723A("link_timer_hdl: assoc timeout and try again\n");
5404                issue_assocreq(padapter);
5405                set_link_timer(pmlmeext, REASSOC_TO);
5406        }
5407
5408        return;
5409}
5410
5411static void addba_timer_hdl(unsigned long data)
5412{
5413        struct sta_info *psta = (struct sta_info *)data;
5414        struct ht_priv *phtpriv;
5415
5416        if (!psta)
5417                return;
5418
5419        phtpriv = &psta->htpriv;
5420
5421        if (phtpriv->ht_option && phtpriv->ampdu_enable) {
5422                if (phtpriv->candidate_tid_bitmap)
5423                        phtpriv->candidate_tid_bitmap = 0x0;
5424        }
5425}
5426
5427void init_addba_retry_timer23a(struct sta_info *psta)
5428{
5429        setup_timer(&psta->addba_retry_timer, addba_timer_hdl,
5430                    (unsigned long)psta);
5431}
5432
5433void init_mlme_ext_timer23a(struct rtw_adapter *padapter)
5434{
5435        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5436
5437        setup_timer(&pmlmeext->survey_timer, survey_timer_hdl,
5438                    (unsigned long)padapter);
5439
5440        setup_timer(&pmlmeext->link_timer, link_timer_hdl,
5441                    (unsigned long)padapter);
5442}
5443
5444int NULL_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
5445{
5446        return H2C_SUCCESS;
5447}
5448
5449int setopmode_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
5450{
5451        enum nl80211_iftype type;
5452        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5453        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
5454        const struct setopmode_parm *psetop = (struct setopmode_parm *)pbuf;
5455
5456        switch (psetop->mode) {
5457        case NL80211_IFTYPE_P2P_GO:
5458        case NL80211_IFTYPE_AP:
5459                pmlmeinfo->state = MSR_AP;
5460                type = MSR_AP;
5461                break;
5462        case NL80211_IFTYPE_P2P_CLIENT:
5463        case NL80211_IFTYPE_STATION:
5464                /*  clear state */
5465                pmlmeinfo->state &= ~(BIT(0)|BIT(1));
5466                /* set to STATION_STATE */
5467                pmlmeinfo->state |= MSR_INFRA;
5468                type = MSR_INFRA;
5469                break;
5470        case NL80211_IFTYPE_ADHOC:
5471                type = MSR_ADHOC;
5472                break;
5473        default:
5474                type = MSR_NOLINK;
5475                break;
5476        }
5477
5478        hw_var_set_opmode(padapter, type);
5479        /* Set_NETYPE0_MSR(padapter, type); */
5480
5481        return H2C_SUCCESS;
5482}
5483
5484int createbss_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
5485{
5486        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5487        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
5488        struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
5489        const struct wlan_bssid_ex *pparm = (struct wlan_bssid_ex *)pbuf;
5490        /* u32  initialgain; */
5491
5492        if (pparm->ifmode == NL80211_IFTYPE_AP ||
5493            pparm->ifmode == NL80211_IFTYPE_P2P_GO) {
5494#ifdef CONFIG_8723AU_AP_MODE
5495                if (pmlmeinfo->state == MSR_AP) {
5496                        /* todo: */
5497                        return H2C_SUCCESS;
5498                }
5499#endif
5500        }
5501
5502        /* below is for ad-hoc master */
5503        if (pparm->ifmode == NL80211_IFTYPE_ADHOC) {
5504                rtw_joinbss_reset23a(padapter);
5505
5506                pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
5507                pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
5508                pmlmeinfo->ERP_enable = 0;
5509                pmlmeinfo->WMM_enable = 0;
5510                pmlmeinfo->HT_enable = 0;
5511                pmlmeinfo->HT_caps_enable = 0;
5512                pmlmeinfo->HT_info_enable = 0;
5513
5514                /* disable dynamic functions, such as high power, DIG */
5515                rtl8723a_odm_support_ability_backup(padapter);
5516
5517                rtl8723a_odm_support_ability_clr(padapter,
5518                                                 DYNAMIC_FUNC_DISABLE);
5519
5520                /* cancel link timer */
5521                del_timer_sync(&pmlmeext->link_timer);
5522
5523                /* clear CAM */
5524                flush_all_cam_entry23a(padapter);
5525
5526                if (pparm->IELength > MAX_IE_SZ)/* Check pbuf->IELength */
5527                        return H2C_PARAMETERS_ERROR;
5528
5529                memcpy(pnetwork, pparm, sizeof(struct wlan_bssid_ex));
5530
5531                start_create_ibss(padapter);
5532        }
5533
5534        return H2C_SUCCESS;
5535}
5536
5537int join_cmd_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
5538{
5539        struct registry_priv *pregpriv = &padapter->registrypriv;
5540        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5541        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
5542        struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
5543        const struct wlan_bssid_ex *pparm = (struct wlan_bssid_ex *)pbuf;
5544        struct ieee80211_ht_operation *pht_info;
5545        u32 i;
5546        u8 *p;
5547        /* u32  initialgain; */
5548        /* u32  acparm; */
5549
5550        /* check already connecting to AP or not */
5551        if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) {
5552                if (pmlmeinfo->state & MSR_INFRA)
5553                        issue_deauth_ex(padapter, pnetwork->MacAddress,
5554                                        WLAN_REASON_DEAUTH_LEAVING, 5, 100);
5555
5556                pmlmeinfo->state = MSR_NOLINK;
5557
5558                /* clear CAM */
5559                flush_all_cam_entry23a(padapter);
5560
5561                del_timer_sync(&pmlmeext->link_timer);
5562
5563                /* set MSR to nolink -> infra. mode */
5564                rtl8723a_set_media_status(padapter, MSR_INFRA);
5565
5566                hw_var_set_mlme_disconnect(padapter);
5567        }
5568
5569        rtw_joinbss_reset23a(padapter);
5570
5571        pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
5572        pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
5573        pmlmeinfo->ERP_enable = 0;
5574        pmlmeinfo->WMM_enable = 0;
5575        pmlmeinfo->HT_enable = 0;
5576        pmlmeinfo->HT_caps_enable = 0;
5577        pmlmeinfo->HT_info_enable = 0;
5578        pmlmeinfo->bwmode_updated = false;
5579        /* pmlmeinfo->assoc_AP_vendor = HT_IOT_PEER_MAX; */
5580
5581        if (pparm->IELength > MAX_IE_SZ)/* Check pbuf->IELength */
5582                return H2C_PARAMETERS_ERROR;
5583
5584        memcpy(pnetwork, pbuf, sizeof(struct wlan_bssid_ex));
5585
5586        /* Check AP vendor to move rtw_joinbss_cmd23a() */
5587        /* pmlmeinfo->assoc_AP_vendor = check_assoc_AP23a(pnetwork->IEs,
5588           pnetwork->IELength); */
5589
5590        for (i = 0; i < pnetwork->IELength;) {
5591                p = pnetwork->IEs + i;
5592
5593                switch (p[0]) {
5594                case WLAN_EID_VENDOR_SPECIFIC:/* Get WMM IE. */
5595                        if (!memcmp(p + 2, WMM_OUI23A, 4))
5596                                pmlmeinfo->WMM_enable = 1;
5597                        break;
5598
5599                case WLAN_EID_HT_CAPABILITY:    /* Get HT Cap IE. */
5600                        pmlmeinfo->HT_caps_enable = 1;
5601                        break;
5602
5603                case WLAN_EID_HT_OPERATION:     /* Get HT Info IE. */
5604                        pmlmeinfo->HT_info_enable = 1;
5605
5606                        /* spec case only for cisco's ap because cisco's ap
5607                         * issue assoc rsp using mcs rate @40MHz or @20MHz */
5608                        pht_info = (struct ieee80211_ht_operation *)(p + 2);
5609
5610                        if (pregpriv->cbw40_enable &&
5611                            (pht_info->ht_param &
5612                             IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
5613                                /* switch to the 40M Hz mode according to AP */
5614                                pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40;
5615                                switch (pht_info->ht_param &
5616                                        IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
5617                                case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
5618                                        pmlmeext->cur_ch_offset =
5619                                                HAL_PRIME_CHNL_OFFSET_LOWER;
5620                                        break;
5621
5622                                case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
5623                                        pmlmeext->cur_ch_offset =
5624                                                HAL_PRIME_CHNL_OFFSET_UPPER;
5625                                        break;
5626
5627                                default:
5628                                        pmlmeext->cur_ch_offset =
5629                                                HAL_PRIME_CHNL_OFFSET_DONT_CARE;
5630                                        break;
5631                                }
5632
5633                                DBG_8723A("set ch/bw before connected\n");
5634                        }
5635                        break;
5636
5637                default:
5638                        break;
5639                }
5640
5641                i += (p[1] + 2);
5642        }
5643
5644        hw_var_set_bssid(padapter, pmlmeinfo->network.MacAddress);
5645        hw_var_set_mlme_join(padapter, 0);
5646
5647        /* cancel link timer */
5648        del_timer_sync(&pmlmeext->link_timer);
5649
5650        start_clnt_join(padapter);
5651
5652        return H2C_SUCCESS;
5653}
5654
5655int disconnect_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
5656{
5657        const struct disconnect_parm *param = (struct disconnect_parm *)pbuf;
5658        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5659        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
5660        struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
5661
5662        if (is_client_associated_to_ap23a(padapter)) {
5663                issue_deauth_ex(padapter, pnetwork->MacAddress,
5664                                WLAN_REASON_DEAUTH_LEAVING,
5665                                param->deauth_timeout_ms/100, 100);
5666        }
5667
5668        /* set_opmode_cmd(padapter, infra_client_with_mlme); */
5669
5670        /* pmlmeinfo->state = MSR_NOLINK; */
5671
5672        hw_var_set_mlme_disconnect(padapter);
5673        hw_var_set_bssid(padapter, null_addr);
5674
5675        /* restore to initial setting. */
5676        update_tx_basic_rate23a(padapter, padapter->registrypriv.wireless_mode);
5677
5678        if ((pmlmeinfo->state & 0x03) == MSR_ADHOC ||
5679            (pmlmeinfo->state & 0x03) == MSR_AP)
5680                rtl8723a_set_bcn_func(padapter, 0);     /* Stop BCN */
5681
5682        /* set MSR to no link state -> infra. mode */
5683        rtl8723a_set_media_status(padapter, MSR_INFRA);
5684
5685        pmlmeinfo->state = MSR_NOLINK;
5686
5687        /* switch to the 20M Hz mode after disconnect */
5688        pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
5689        pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
5690
5691        set_channel_bwmode23a(padapter, pmlmeext->cur_channel,
5692                              pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
5693
5694        flush_all_cam_entry23a(padapter);
5695
5696        del_timer_sync(&pmlmeext->link_timer);
5697
5698        rtw_free_uc_swdec_pending_queue23a(padapter);
5699
5700        return H2C_SUCCESS;
5701}
5702
5703static int
5704rtw_scan_ch_decision(struct rtw_adapter *padapter,
5705                     struct rtw_ieee80211_channel *out, u32 out_num,
5706                     const struct rtw_ieee80211_channel *in, u32 in_num)
5707{
5708        int i, j;
5709        int scan_ch_num = 0;
5710        int set_idx;
5711        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5712
5713        /* clear out first */
5714        memset(out, 0, sizeof(struct rtw_ieee80211_channel)*out_num);
5715
5716        /* acquire channels from in */
5717        j = 0;
5718        for (i = 0;i<in_num;i++) {
5719                if (in[i].hw_value &&
5720                    !(in[i].flags & IEEE80211_CHAN_DISABLED) &&
5721                    (set_idx = rtw_ch_set_search_ch23a(pmlmeext->channel_set,
5722                                                       in[i].hw_value)) >= 0) {
5723                        memcpy(&out[j], &in[i],
5724                               sizeof(struct rtw_ieee80211_channel));
5725
5726                        if (pmlmeext->channel_set[set_idx].ScanType ==
5727                            SCAN_PASSIVE)
5728                                out[j].flags &= IEEE80211_CHAN_NO_IR;
5729
5730                        j++;
5731                }
5732                if (j>= out_num)
5733                        break;
5734        }
5735
5736        /* if out is empty, use channel_set as default */
5737        if (j == 0) {
5738                for (i = 0;i<pmlmeext->max_chan_nums;i++) {
5739                        out[i].hw_value = pmlmeext->channel_set[i].ChannelNum;
5740
5741                        if (pmlmeext->channel_set[i].ScanType == SCAN_PASSIVE)
5742                                out[i].flags &= IEEE80211_CHAN_NO_IR;
5743
5744                        j++;
5745                }
5746        }
5747
5748        if (padapter->setband == GHZ_24) {                      /*  2.4G */
5749                for (i = 0; i < j ; i++) {
5750                        if (out[i].hw_value > 35)
5751                                memset(&out[i], 0,
5752                                       sizeof(struct rtw_ieee80211_channel));
5753                        else
5754                                scan_ch_num++;
5755                }
5756                j = scan_ch_num;
5757        } else if  (padapter->setband == GHZ_50) {              /*  5G */
5758                for (i = 0; i < j ; i++) {
5759                        if (out[i].hw_value > 35) {
5760                                memcpy(&out[scan_ch_num++], &out[i],
5761                                       sizeof(struct rtw_ieee80211_channel));
5762                        }
5763                }
5764                j = scan_ch_num;
5765        } else
5766                {}
5767
5768        return j;
5769}
5770
5771int sitesurvey_cmd_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
5772{
5773        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5774        const struct sitesurvey_parm *pparm = (struct sitesurvey_parm *)pbuf;
5775        u8 bdelayscan = false;
5776        u32 initialgain;
5777        u32 i;
5778
5779        if (pmlmeext->sitesurvey_res.state == SCAN_DISABLE) {
5780                pmlmeext->sitesurvey_res.state = SCAN_START;
5781                pmlmeext->sitesurvey_res.bss_cnt = 0;
5782                pmlmeext->sitesurvey_res.channel_idx = 0;
5783
5784                for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) {
5785                        if (pparm->ssid[i].ssid_len) {
5786                                memcpy(pmlmeext->sitesurvey_res.ssid[i].ssid,
5787                                       pparm->ssid[i].ssid,
5788                                       IEEE80211_MAX_SSID_LEN);
5789                                pmlmeext->sitesurvey_res.ssid[i].ssid_len =
5790                                        pparm->ssid[i].ssid_len;
5791                        } else {
5792                                pmlmeext->sitesurvey_res.ssid[i].ssid_len = 0;
5793                        }
5794                }
5795
5796                pmlmeext->sitesurvey_res.ch_num =
5797                        rtw_scan_ch_decision(padapter,
5798                                             pmlmeext->sitesurvey_res.ch,
5799                                             RTW_CHANNEL_SCAN_AMOUNT,
5800                                             pparm->ch, pparm->ch_num);
5801
5802                pmlmeext->sitesurvey_res.scan_mode = pparm->scan_mode;
5803
5804                /* issue null data if associating to the AP */
5805                if (is_client_associated_to_ap23a(padapter)) {
5806                        pmlmeext->sitesurvey_res.state = SCAN_TXNULL;
5807
5808                        /* switch to correct channel of current network
5809                           before issue keep-alive frames */
5810                        if (rtw_get_oper_ch23a(padapter) !=
5811                            pmlmeext->cur_channel)
5812                                SelectChannel23a(padapter,
5813                                                 pmlmeext->cur_channel);
5814
5815                        issue_nulldata23a(padapter, NULL, 1, 3, 500);
5816
5817                        bdelayscan = true;
5818                }
5819
5820                if (bdelayscan) {
5821                        /* delay 50ms to protect nulldata(1). */
5822                        set_survey_timer(pmlmeext, 50);
5823                        return H2C_SUCCESS;
5824                }
5825        }
5826
5827        if (pmlmeext->sitesurvey_res.state == SCAN_START ||
5828            pmlmeext->sitesurvey_res.state == SCAN_TXNULL) {
5829                /* disable dynamic functions, such as high power, DIG */
5830                rtl8723a_odm_support_ability_backup(padapter);
5831                rtl8723a_odm_support_ability_clr(padapter,
5832                                                 DYNAMIC_FUNC_DISABLE);
5833
5834                /* config the initial gain under scanning, need to
5835                   write the BB registers */
5836                if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled == true)
5837                        initialgain = 0x30;
5838                else
5839                        initialgain = 0x1E;
5840
5841                rtl8723a_set_initial_gain(padapter, initialgain);
5842
5843                /* set MSR to no link state */
5844                rtl8723a_set_media_status(padapter, MSR_NOLINK);
5845
5846                rtl8723a_mlme_sitesurvey(padapter, 1);
5847
5848                pmlmeext->sitesurvey_res.state = SCAN_PROCESS;
5849        }
5850
5851        rtw_site_survey(padapter);
5852
5853        return H2C_SUCCESS;
5854}
5855
5856int setauth_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
5857{
5858        const struct setauth_parm *pparm = (struct setauth_parm *)pbuf;
5859        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5860        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
5861
5862        if (pparm->mode < 4)
5863                pmlmeinfo->auth_algo = pparm->mode;
5864
5865        return H2C_SUCCESS;
5866}
5867
5868int setkey_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
5869{
5870        unsigned short ctrl;
5871        const struct setkey_parm *pparm = (struct setkey_parm *)pbuf;
5872        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5873        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
5874        unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
5875
5876        /* main tx key for wep. */
5877        if (pparm->set_tx)
5878                pmlmeinfo->key_index = pparm->keyid;
5879
5880        /* write cam */
5881        ctrl = BIT(15) | (pparm->algorithm) << 2 | pparm->keyid;
5882
5883        DBG_8723A_LEVEL(_drv_always_, "set group key to hw: alg:%d(WEP40-1 "
5884                        "WEP104-5 TKIP-2 AES-4) keyid:%d\n",
5885                        pparm->algorithm, pparm->keyid);
5886        rtl8723a_cam_write(padapter, pparm->keyid, ctrl, null_sta, pparm->key);
5887
5888        /* allow multicast packets to driver */
5889        rtl8723a_on_rcr_am(padapter);
5890
5891        return H2C_SUCCESS;
5892}
5893
5894int set_stakey_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
5895{
5896        u16 ctrl = 0;
5897        u8 cam_id;/* cam_entry */
5898        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5899        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
5900        const struct set_stakey_parm *pparm = (struct set_stakey_parm *)pbuf;
5901
5902        /* cam_entry: */
5903        /* 0~3 for default key */
5904
5905        /* for concurrent mode (ap+sta): */
5906        /* default key is disable, using sw encrypt/decrypt */
5907        /* cam_entry = 4  for sta mode (macid = 0) */
5908        /* cam_entry(macid+3) = 5 ~ N for ap mode (aid = 1~N, macid = 2 ~N) */
5909
5910        /* for concurrent mode (sta+sta): */
5911        /* default key is disable, using sw encrypt/decrypt */
5912        /* cam_entry = 4 mapping to macid = 0 */
5913        /* cam_entry = 5 mapping to macid = 2 */
5914
5915        cam_id = 4;
5916
5917        DBG_8723A_LEVEL(_drv_always_, "set pairwise key to hw: alg:%d(WEP40-1 "
5918                        "WEP104-5 TKIP-2 AES-4) camid:%d\n",
5919                        pparm->algorithm, cam_id);
5920        if ((pmlmeinfo->state & 0x03) == MSR_AP) {
5921                struct sta_info *psta;
5922                struct sta_priv *pstapriv = &padapter->stapriv;
5923
5924                if (pparm->algorithm == 0) {    /*  clear cam entry */
5925                        clear_cam_entry23a(padapter, pparm->id);
5926                        return H2C_SUCCESS_RSP;
5927                }
5928
5929                psta = rtw_get_stainfo23a(pstapriv, pparm->addr);
5930                if (psta) {
5931                        ctrl = BIT(15) | (pparm->algorithm << 2);
5932
5933                        DBG_8723A("r871x_set_stakey_hdl23a(): enc_algorithm "
5934                                  "=%d\n", pparm->algorithm);
5935
5936                        if (psta->mac_id < 1 || psta->mac_id > (NUM_STA - 4)) {
5937                                DBG_8723A("r871x_set_stakey_hdl23a():set_stakey"
5938                                          " failed, mac_id(aid) =%d\n",
5939                                          psta->mac_id);
5940                                return H2C_REJECTED;
5941                        }
5942
5943                        /* 0~3 for default key, cmd_id = macid + 3,
5944                           macid = aid+1; */
5945                        cam_id = psta->mac_id + 3;
5946
5947                        DBG_8723A("Write CAM, mac_addr =%x:%x:%x:%x:%x:%x, "
5948                                  "cam_entry =%d\n", pparm->addr[0],
5949                                  pparm->addr[1], pparm->addr[2],
5950                                  pparm->addr[3], pparm->addr[4],
5951                                  pparm->addr[5], cam_id);
5952
5953                        rtl8723a_cam_write(padapter, cam_id, ctrl,
5954                                           pparm->addr, pparm->key);
5955
5956                        return H2C_SUCCESS_RSP;
5957                } else {
5958                        DBG_8723A("r871x_set_stakey_hdl23a(): sta has been "
5959                                  "free\n");
5960                        return H2C_REJECTED;
5961                }
5962        }
5963
5964        /* below for sta mode */
5965
5966        if (pparm->algorithm == 0) {    /*  clear cam entry */
5967                clear_cam_entry23a(padapter, pparm->id);
5968                return H2C_SUCCESS;
5969        }
5970
5971        ctrl = BIT(15) | (pparm->algorithm << 2);
5972
5973        rtl8723a_cam_write(padapter, cam_id, ctrl, pparm->addr, pparm->key);
5974
5975        pmlmeinfo->enc_algo = pparm->algorithm;
5976
5977        return H2C_SUCCESS;
5978}
5979
5980int add_ba_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
5981{
5982        const struct addBaReq_parm *pparm = (struct addBaReq_parm *)pbuf;
5983        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
5984        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
5985        struct sta_info *psta;
5986
5987        psta = rtw_get_stainfo23a(&padapter->stapriv, pparm->addr);
5988
5989        if (!psta)
5990                return H2C_SUCCESS;
5991
5992        if (((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) &&
5993             pmlmeinfo->HT_enable) ||
5994            (pmlmeinfo->state & 0x03) == MSR_AP) {
5995                issue_action_BA23a(padapter, pparm->addr,
5996                                   WLAN_ACTION_ADDBA_REQ, (u16)pparm->tid);
5997                mod_timer(&psta->addba_retry_timer,
5998                          jiffies + msecs_to_jiffies(ADDBA_TO));
5999        } else
6000                psta->htpriv.candidate_tid_bitmap &= ~BIT(pparm->tid);
6001
6002        return H2C_SUCCESS;
6003}
6004
6005int set_tx_beacon_cmd23a(struct rtw_adapter *padapter)
6006{
6007        struct cmd_obj *ph2c;
6008        struct Tx_Beacon_param *ptxBeacon_parm;
6009        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
6010        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
6011        struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
6012        u8 res = _SUCCESS;
6013        int len_diff = 0;
6014
6015        ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
6016        if (!ph2c) {
6017                res = _FAIL;
6018                goto exit;
6019        }
6020
6021        ptxBeacon_parm = kzalloc(sizeof(struct Tx_Beacon_param), GFP_ATOMIC);
6022        if (!ptxBeacon_parm) {
6023                kfree(ph2c);
6024                res = _FAIL;
6025                goto exit;
6026        }
6027
6028        memcpy(&ptxBeacon_parm->network, &pmlmeinfo->network,
6029               sizeof(struct wlan_bssid_ex));
6030
6031        len_diff = update_hidden_ssid(ptxBeacon_parm->network.IEs,
6032                                      ptxBeacon_parm->network.IELength,
6033                                      pmlmeinfo->hidden_ssid_mode);
6034        ptxBeacon_parm->network.IELength += len_diff;
6035
6036        init_h2fwcmd_w_parm_no_rsp(ph2c, ptxBeacon_parm,
6037                                   GEN_CMD_CODE(_TX_Beacon));
6038
6039        res = rtw_enqueue_cmd23a(pcmdpriv, ph2c);
6040
6041exit:
6042        return res;
6043}
6044
6045int mlme_evt_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
6046{
6047        u8 evt_code, evt_seq;
6048        u16 evt_sz;
6049        const struct C2HEvent_Header *c2h;
6050        void (*event_callback)(struct rtw_adapter *dev, const u8 *pbuf);
6051
6052        c2h = (struct C2HEvent_Header *)pbuf;
6053        evt_sz = c2h->len;
6054        evt_seq = c2h->seq;
6055        evt_code = c2h->ID;
6056
6057        /*  checking if event code is valid */
6058        if (evt_code >= MAX_C2HEVT) {
6059                RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
6060                         "Event Code(%d) mismatch!\n", evt_code);
6061                goto _abort_event_;
6062        }
6063
6064        /*  checking if event size match the event parm size */
6065        if (wlanevents[evt_code].parmsize != 0 &&
6066            wlanevents[evt_code].parmsize != evt_sz) {
6067                RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
6068                         "Event(%d) Parm Size mismatch (%d vs %d)!\n",
6069                         evt_code, wlanevents[evt_code].parmsize, evt_sz);
6070                goto _abort_event_;
6071        }
6072
6073        event_callback = wlanevents[evt_code].event_callback;
6074        event_callback(padapter, pbuf + sizeof(struct C2HEvent_Header));
6075
6076_abort_event_:
6077
6078        return H2C_SUCCESS;
6079}
6080
6081int h2c_msg_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
6082{
6083        if (!pbuf)
6084                return H2C_PARAMETERS_ERROR;
6085
6086        return H2C_SUCCESS;
6087}
6088
6089int tx_beacon_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
6090{
6091        if (send_beacon23a(padapter) == _FAIL) {
6092                DBG_8723A("issue_beacon23a, fail!\n");
6093                return H2C_PARAMETERS_ERROR;
6094        }
6095#ifdef CONFIG_8723AU_AP_MODE
6096        else { /* tx bc/mc frames after update TIM */
6097                struct sta_info *psta_bmc;
6098                struct list_head *plist, *phead, *ptmp;
6099                struct xmit_frame *pxmitframe;
6100                struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
6101                struct sta_priv  *pstapriv = &padapter->stapriv;
6102
6103                /* for BC/MC Frames */
6104                psta_bmc = rtw_get_bcmc_stainfo23a(padapter);
6105                if (!psta_bmc)
6106                        return H2C_SUCCESS;
6107
6108                if (pstapriv->tim_bitmap & BIT(0) && psta_bmc->sleepq_len > 0) {
6109                        msleep(10);/*  10ms, ATIM(HIQ) Windows */
6110                        /* spin_lock_bh(&psta_bmc->sleep_q.lock); */
6111                        spin_lock_bh(&pxmitpriv->lock);
6112
6113                        phead = get_list_head(&psta_bmc->sleep_q);
6114
6115                        list_for_each_safe(plist, ptmp, phead) {
6116                                pxmitframe = container_of(plist,
6117                                                          struct xmit_frame,
6118                                                          list);
6119
6120                                list_del_init(&pxmitframe->list);
6121
6122                                psta_bmc->sleepq_len--;
6123                                if (psta_bmc->sleepq_len>0)
6124                                        pxmitframe->attrib.mdata = 1;
6125                                else
6126                                        pxmitframe->attrib.mdata = 0;
6127
6128                                pxmitframe->attrib.triggered = 1;
6129
6130                                pxmitframe->attrib.qsel = 0x11;/* HIQ */
6131
6132                                rtl8723au_hal_xmitframe_enqueue(padapter,
6133                                                                pxmitframe);
6134                        }
6135
6136                        /* spin_unlock_bh(&psta_bmc->sleep_q.lock); */
6137                        spin_unlock_bh(&pxmitpriv->lock);
6138                }
6139        }
6140#endif
6141
6142        return H2C_SUCCESS;
6143}
6144
6145int set_ch_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
6146{
6147        const struct set_ch_parm *set_ch_parm;
6148        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
6149
6150        if (!pbuf)
6151                return H2C_PARAMETERS_ERROR;
6152
6153        set_ch_parm = (struct set_ch_parm *)pbuf;
6154
6155        DBG_8723A("%s(%s): ch:%u, bw:%u, ch_offset:%u\n", __func__,
6156                  padapter->pnetdev->name, set_ch_parm->ch,
6157                  set_ch_parm->bw, set_ch_parm->ch_offset);
6158
6159        pmlmeext->cur_channel = set_ch_parm->ch;
6160        pmlmeext->cur_ch_offset = set_ch_parm->ch_offset;
6161        pmlmeext->cur_bwmode = set_ch_parm->bw;
6162
6163        set_channel_bwmode23a(padapter, set_ch_parm->ch,
6164                              set_ch_parm->ch_offset, set_ch_parm->bw);
6165
6166        return H2C_SUCCESS;
6167}
6168
6169int set_chplan_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
6170{
6171        const struct SetChannelPlan_param *setChannelPlan_param;
6172        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
6173
6174        if (!pbuf)
6175                return H2C_PARAMETERS_ERROR;
6176
6177        setChannelPlan_param = (struct SetChannelPlan_param *)pbuf;
6178
6179        pmlmeext->max_chan_nums =
6180                init_channel_set(padapter, setChannelPlan_param->channel_plan,
6181                                 pmlmeext->channel_set);
6182        init_channel_list(padapter, pmlmeext->channel_set,
6183                          pmlmeext->max_chan_nums, &pmlmeext->channel_list);
6184
6185        return H2C_SUCCESS;
6186}
6187
6188int led_blink_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
6189{
6190        struct LedBlink_param *ledBlink_param;
6191
6192        if (!pbuf)
6193                return H2C_PARAMETERS_ERROR;
6194
6195        ledBlink_param = (struct LedBlink_param *)pbuf;
6196
6197        return H2C_SUCCESS;
6198}
6199
6200int set_csa_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
6201{
6202        return H2C_REJECTED;
6203}
6204
6205/*  TDLS_WRCR           : write RCR DATA BIT */
6206/*  TDLS_SD_PTI         : issue peer traffic indication */
6207/*  TDLS_CS_OFF         : go back to the channel linked with AP,
6208                          terminating channel switch procedure */
6209/*  TDLS_INIT_CH_SEN    : init channel sensing, receive all data and
6210                          mgnt frame */
6211/*  TDLS_DONE_CH_SEN    : channel sensing and report candidate channel */
6212/*  TDLS_OFF_CH         : first time set channel to off channel */
6213/*  TDLS_BASE_CH        : go back tp the channel linked with AP when set
6214                          base channel as target channel */
6215/*  TDLS_P_OFF_CH       : periodically go to off channel */
6216/*  TDLS_P_BASE_CH      : periodically go back to base channel */
6217/*  TDLS_RS_RCR         : restore RCR */
6218/*  TDLS_CKALV_PH1      : check alive timer phase1 */
6219/*  TDLS_CKALV_PH2      : check alive timer phase2 */
6220/*  TDLS_FREE_STA       : free tdls sta */
6221int tdls_hdl23a(struct rtw_adapter *padapter, const u8 *pbuf)
6222{
6223        return H2C_REJECTED;
6224}
6225