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