GNU Linux-libre 5.10.219-gnu1
[releases.git] / drivers / staging / rtl8188eu / core / rtw_cmd.c
1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  *
4  * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
5  *
6  ******************************************************************************/
7 #define _RTW_CMD_C_
8
9 #include <osdep_service.h>
10 #include <drv_types.h>
11 #include <recv_osdep.h>
12 #include <mlme_osdep.h>
13 #include <rtw_mlme_ext.h>
14
15 /*
16  * Caller and the rtw_cmd_thread can protect cmd_q by spin_lock.
17  * No irqsave is necessary.
18  */
19
20 int rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
21 {
22         init_completion(&pcmdpriv->cmd_queue_comp);
23         init_completion(&pcmdpriv->terminate_cmdthread_comp);
24
25         _rtw_init_queue(&pcmdpriv->cmd_queue);
26         return _SUCCESS;
27 }
28
29 /*
30  * Calling Context:
31  *
32  * rtw_enqueue_cmd can only be called between kernel thread,
33  * since only spin_lock is used.
34  *
35  * ISR/Call-Back functions can't call this sub-function.
36  */
37
38 static int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj)
39 {
40         unsigned long irqL;
41
42         if (!obj)
43                 goto exit;
44
45         spin_lock_irqsave(&queue->lock, irqL);
46
47         list_add_tail(&obj->list, &queue->queue);
48
49         spin_unlock_irqrestore(&queue->lock, irqL);
50
51 exit:
52
53         return _SUCCESS;
54 }
55
56 struct cmd_obj *rtw_dequeue_cmd(struct __queue *queue)
57 {
58         unsigned long irqL;
59         struct cmd_obj *obj;
60
61         spin_lock_irqsave(&queue->lock, irqL);
62         obj = list_first_entry_or_null(&queue->queue, struct cmd_obj, list);
63         if (obj)
64                 list_del_init(&obj->list);
65         spin_unlock_irqrestore(&queue->lock, irqL);
66
67         return obj;
68 }
69
70 static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
71 {
72         u8 bAllow = false; /* set to true to allow enqueuing cmd when hw_init_completed is false */
73
74         /* To decide allow or not */
75         if ((pcmdpriv->padapter->pwrctrlpriv.bHWPwrPindetect) &&
76             (!pcmdpriv->padapter->registrypriv.usbss_enable)) {
77                 if (cmd_obj->cmdcode == _Set_Drv_Extra_CMD_) {
78                         struct drvextra_cmd_parm        *pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)cmd_obj->parmbuf;
79
80                         if (pdrvextra_cmd_parm->ec_id == POWER_SAVING_CTRL_WK_CID)
81                                 bAllow = true;
82                 }
83         }
84
85         if (cmd_obj->cmdcode == _SetChannelPlan_CMD_)
86                 bAllow = true;
87
88         if ((!pcmdpriv->padapter->hw_init_completed && !bAllow) ||
89             !pcmdpriv->cmdthd_running)  /* com_thread not running */
90                 return _FAIL;
91         return _SUCCESS;
92 }
93
94 u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
95 {
96         int res = _FAIL;
97         struct adapter *padapter = pcmdpriv->padapter;
98
99         if (!cmd_obj)
100                 goto exit;
101
102         cmd_obj->padapter = padapter;
103
104         res = rtw_cmd_filter(pcmdpriv, cmd_obj);
105         if (res == _FAIL) {
106                 rtw_free_cmd_obj(cmd_obj);
107                 goto exit;
108         }
109
110         res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj);
111
112         if (res == _SUCCESS)
113                 complete(&pcmdpriv->cmd_queue_comp);
114
115 exit:
116
117         return res;
118 }
119
120 void rtw_free_cmd_obj(struct cmd_obj *pcmd)
121 {
122         if ((pcmd->cmdcode != _JoinBss_CMD_) && (pcmd->cmdcode != _CreateBss_CMD_)) {
123                 /* free parmbuf in cmd_obj */
124                 kfree(pcmd->parmbuf);
125         }
126
127         if (pcmd->rsp) {
128                 if (pcmd->rspsz != 0) {
129                         /* free rsp in cmd_obj */
130                         kfree(pcmd->rsp);
131                 }
132         }
133
134         /* free cmd_obj */
135         kfree(pcmd);
136 }
137
138 int rtw_cmd_thread(void *context)
139 {
140         u8 ret;
141         struct cmd_obj *pcmd;
142         u8 (*cmd_hdl)(struct adapter *padapter, u8 *pbuf);
143         void (*pcmd_callback)(struct adapter *dev, struct cmd_obj *pcmd);
144         struct adapter *padapter = context;
145         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
146
147         allow_signal(SIGTERM);
148
149         pcmdpriv->cmdthd_running = true;
150         complete(&pcmdpriv->terminate_cmdthread_comp);
151
152         RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
153                  ("start r871x %s !!!!\n", __func__));
154
155         while (1) {
156                 if (wait_for_completion_interruptible(&pcmdpriv->cmd_queue_comp))
157                         break;
158
159                 if (padapter->bDriverStopped ||
160                     padapter->bSurpriseRemoved) {
161                         DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n",
162                                 __func__, padapter->bDriverStopped,
163                                 padapter->bSurpriseRemoved, __LINE__);
164                         break;
165                 }
166 _next:
167                 if (padapter->bDriverStopped ||
168                     padapter->bSurpriseRemoved) {
169                         DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n",
170                                 __func__, padapter->bDriverStopped,
171                                 padapter->bSurpriseRemoved, __LINE__);
172                         break;
173                 }
174
175                 pcmd = rtw_dequeue_cmd(&pcmdpriv->cmd_queue);
176                 if (!pcmd)
177                         continue;
178
179                 if (rtw_cmd_filter(pcmdpriv, pcmd) == _FAIL) {
180                         pcmd->res = H2C_DROPPED;
181                 } else {
182                         if (pcmd->cmdcode < ARRAY_SIZE(wlancmds)) {
183                                 cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns;
184
185                                 if (cmd_hdl) {
186                                         ret = cmd_hdl(pcmd->padapter, pcmd->parmbuf);
187                                         pcmd->res = ret;
188                                 }
189                         } else {
190                                 pcmd->res = H2C_PARAMETERS_ERROR;
191                         }
192
193                         cmd_hdl = NULL;
194                 }
195
196                 /* call callback function for post-processed */
197                 if (pcmd->cmdcode < ARRAY_SIZE(rtw_cmd_callback)) {
198                         pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback;
199                         if (!pcmd_callback) {
200                                 RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
201                                          ("mlme_cmd_hdl(): pcmd_callback = 0x%p, cmdcode = 0x%x\n",
202                                           pcmd_callback, pcmd->cmdcode));
203                                 rtw_free_cmd_obj(pcmd);
204                         } else {
205                                 /* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */
206                                 pcmd_callback(pcmd->padapter, pcmd);/* need consider that free cmd_obj in rtw_cmd_callback */
207                         }
208                 } else {
209                         RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
210                                  ("%s: cmdcode = 0x%x callback not defined!\n",
211                                   __func__, pcmd->cmdcode));
212                         rtw_free_cmd_obj(pcmd);
213                 }
214
215                 if (signal_pending(current))
216                         flush_signals(current);
217
218                 goto _next;
219         }
220         pcmdpriv->cmdthd_running = false;
221
222         /*  free all cmd_obj resources */
223         while ((pcmd = rtw_dequeue_cmd(&pcmdpriv->cmd_queue)))
224                 rtw_free_cmd_obj(pcmd);
225
226         complete(&pcmdpriv->terminate_cmdthread_comp);
227
228         complete_and_exit(NULL, 0);
229 }
230
231 /*
232  * rtw_sitesurvey_cmd(~)
233  * ### NOTE:#### (!!!!)
234  * MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE
235  * LOCKED pmlmepriv->lock
236  */
237 u8 rtw_sitesurvey_cmd(struct adapter  *padapter, struct ndis_802_11_ssid *ssid, int ssid_num,
238                       struct rtw_ieee80211_channel *ch, int ch_num)
239 {
240         u8 res = _FAIL;
241         struct cmd_obj          *ph2c;
242         struct sitesurvey_parm  *psurveyPara;
243         struct cmd_priv         *pcmdpriv = &padapter->cmdpriv;
244         struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
245
246         if (check_fwstate(pmlmepriv, _FW_LINKED))
247                 rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1);
248
249         ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
250         if (!ph2c)
251                 return _FAIL;
252
253         psurveyPara = kzalloc(sizeof(*psurveyPara), GFP_ATOMIC);
254         if (!psurveyPara) {
255                 kfree(ph2c);
256                 return _FAIL;
257         }
258
259         rtw_free_network_queue(padapter, false);
260
261         RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("%s: flush network queue\n", __func__));
262
263         init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, _SiteSurvey_CMD_);
264
265         psurveyPara->scan_mode = pmlmepriv->scan_mode;
266
267         /* prepare ssid list */
268         if (ssid) {
269                 int i;
270
271                 for (i = 0; i < ssid_num && i < RTW_SSID_SCAN_AMOUNT; i++) {
272                         if (ssid[i].ssid_length) {
273                                 memcpy(&psurveyPara->ssid[i], &ssid[i],
274                                        sizeof(struct ndis_802_11_ssid));
275                                 psurveyPara->ssid_num++;
276                         }
277                 }
278         }
279
280         /* prepare channel list */
281         if (ch) {
282                 int i;
283
284                 for (i = 0; i < ch_num && i < RTW_CHANNEL_SCAN_AMOUNT; i++) {
285                         if (ch[i].hw_value && !(ch[i].flags & RTW_IEEE80211_CHAN_DISABLED)) {
286                                 memcpy(&psurveyPara->ch[i], &ch[i],
287                                        sizeof(struct rtw_ieee80211_channel));
288                                 psurveyPara->ch_num++;
289                         }
290                 }
291         }
292
293         set_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
294
295         res = rtw_enqueue_cmd(pcmdpriv, ph2c);
296
297         if (res == _SUCCESS) {
298                 mod_timer(&pmlmepriv->scan_to_timer,
299                           jiffies + msecs_to_jiffies(SCANNING_TIMEOUT));
300
301                 led_control_8188eu(padapter, LED_CTL_SITE_SURVEY);
302
303                 pmlmepriv->scan_interval = SCAN_INTERVAL;/*  30*2 sec = 60sec */
304         } else {
305                 _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
306         }
307
308         return res;
309 }
310
311 void rtw_readtssi_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
312 {
313         kfree(pcmd->parmbuf);
314         kfree(pcmd);
315 }
316
317 u8 rtw_createbss_cmd(struct adapter  *padapter)
318 {
319         struct cmd_obj *pcmd;
320         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
321         struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
322         struct wlan_bssid_ex *pdev_network = &padapter->registrypriv.dev_network;
323         u8      res = _SUCCESS;
324
325         led_control_8188eu(padapter, LED_CTL_START_TO_LINK);
326
327         if (pmlmepriv->assoc_ssid.ssid_length == 0)
328                 RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
329                          (" createbss for Any SSid:%s\n", pmlmepriv->assoc_ssid.ssid));
330         else
331                 RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
332                          (" createbss for SSid:%s\n", pmlmepriv->assoc_ssid.ssid));
333
334         pcmd = kzalloc(sizeof(*pcmd), GFP_ATOMIC);
335         if (!pcmd) {
336                 res = _FAIL;
337                 goto exit;
338         }
339
340         INIT_LIST_HEAD(&pcmd->list);
341         pcmd->cmdcode = _CreateBss_CMD_;
342         pcmd->parmbuf = (unsigned char *)pdev_network;
343         pcmd->cmdsz = get_wlan_bssid_ex_sz(pdev_network);
344         pcmd->rsp = NULL;
345         pcmd->rspsz = 0;
346         pdev_network->Length = pcmd->cmdsz;
347         res = rtw_enqueue_cmd(pcmdpriv, pcmd);
348 exit:
349
350         return res;
351 }
352
353 u8 rtw_joinbss_cmd(struct adapter  *padapter, struct wlan_network *pnetwork)
354 {
355         u8      res = _SUCCESS;
356         uint    t_len = 0;
357         struct wlan_bssid_ex            *psecnetwork;
358         struct cmd_obj          *pcmd;
359         struct cmd_priv         *pcmdpriv = &padapter->cmdpriv;
360         struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
361         struct qos_priv         *pqospriv = &pmlmepriv->qospriv;
362         struct security_priv    *psecuritypriv = &padapter->securitypriv;
363         struct registry_priv    *pregistrypriv = &padapter->registrypriv;
364         struct ht_priv          *phtpriv = &pmlmepriv->htpriv;
365         enum ndis_802_11_network_infra ndis_network_mode = pnetwork->network.InfrastructureMode;
366         struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
367         struct mlme_ext_info    *pmlmeinfo = &pmlmeext->mlmext_info;
368
369         led_control_8188eu(padapter, LED_CTL_START_TO_LINK);
370
371         if (pmlmepriv->assoc_ssid.ssid_length == 0)
372                 RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+Join cmd: Any SSid\n"));
373         else
374                 RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_,
375                          ("+Join cmd: SSid =[%s]\n", pmlmepriv->assoc_ssid.ssid));
376
377         pcmd = kzalloc(sizeof(*pcmd), GFP_ATOMIC);
378         if (!pcmd) {
379                 res = _FAIL;
380                 goto exit;
381         }
382         /* for ies is fix buf size */
383         t_len = sizeof(struct wlan_bssid_ex);
384
385         /* for hidden ap to set fw_state here */
386         if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE)) {
387                 switch (ndis_network_mode) {
388                 case Ndis802_11IBSS:
389                         set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
390                         break;
391                 case Ndis802_11Infrastructure:
392                         set_fwstate(pmlmepriv, WIFI_STATION_STATE);
393                         break;
394                 case Ndis802_11APMode:
395                 case Ndis802_11AutoUnknown:
396                 case Ndis802_11InfrastructureMax:
397                         break;
398                 }
399         }
400
401         psecnetwork = &psecuritypriv->sec_bss;
402         if (!psecnetwork) {
403                 kfree(pcmd);
404
405                 res = _FAIL;
406
407                 RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
408                          ("%s :psecnetwork == NULL!!!\n", __func__));
409
410                 goto exit;
411         }
412
413         memset(psecnetwork, 0, t_len);
414
415         memcpy(psecnetwork, &pnetwork->network, get_wlan_bssid_ex_sz(&pnetwork->network));
416
417         psecuritypriv->authenticator_ie[0] = (unsigned char)psecnetwork->ie_length;
418
419         if (psecnetwork->ie_length - 12 < 255)
420                 memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->ies[12],
421                        psecnetwork->ie_length - 12);
422         else
423                 memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->ies[12], 255);
424
425         psecnetwork->ie_length = 0;
426         /*  Added by Albert 2009/02/18 */
427         /*  If the driver wants to use the bssid to create the connection. */
428         /*  If not,  we have to copy the connecting AP's MAC address to it so that */
429         /*  the driver just has the bssid information for PMKIDList searching. */
430
431         if (!pmlmepriv->assoc_by_bssid)
432                 memcpy(&pmlmepriv->assoc_bssid[0], &pnetwork->network.MacAddress[0], ETH_ALEN);
433
434         psecnetwork->ie_length = rtw_restruct_sec_ie(padapter, &pnetwork->network.ies[0],
435                                                      &psecnetwork->ies[0],
436                                                      pnetwork->network.ie_length);
437
438         pqospriv->qos_option = 0;
439
440         if (pregistrypriv->wmm_enable) {
441                 u32 tmp_len;
442
443                 tmp_len = rtw_restruct_wmm_ie(padapter, &pnetwork->network.ies[0],
444                                               &psecnetwork->ies[0],
445                                               pnetwork->network.ie_length,
446                                               psecnetwork->ie_length);
447
448                 if (psecnetwork->ie_length != tmp_len) {
449                         psecnetwork->ie_length = tmp_len;
450                         pqospriv->qos_option = 1; /* There is WMM IE in this corresp. beacon */
451                 } else {
452                         pqospriv->qos_option = 0;/* There is no WMM IE in this corresp. beacon */
453                 }
454         }
455
456         phtpriv->ht_option = false;
457         if (pregistrypriv->ht_enable) {
458                 /*
459                  * Added by Albert 2010/06/23
460                  * For the WEP mode, we will use the bg mode to do
461                  * the connection to avoid some IOT issue.
462                  * Especially for Realtek 8192u SoftAP.
463                  */
464                 if ((padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_) &&
465                     (padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_) &&
466                     (padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_)) {
467                         /* rtw_restructure_ht_ie */
468                         rtw_restructure_ht_ie(padapter, &pnetwork->network.ies[0],
469                                               &psecnetwork->ies[0],
470                                               pnetwork->network.ie_length, &psecnetwork->ie_length);
471                 }
472         }
473
474         pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->network.ies, pnetwork->network.ie_length);
475
476         if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_TENDA)
477                 padapter->pwrctrlpriv.smart_ps = 0;
478         else
479                 padapter->pwrctrlpriv.smart_ps = padapter->registrypriv.smart_ps;
480
481         DBG_88E("%s: smart_ps =%d\n", __func__, padapter->pwrctrlpriv.smart_ps);
482
483         pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork);/* get cmdsz before endian conversion */
484
485         INIT_LIST_HEAD(&pcmd->list);
486         pcmd->cmdcode = _JoinBss_CMD_;
487         pcmd->parmbuf = (unsigned char *)psecnetwork;
488         pcmd->rsp = NULL;
489         pcmd->rspsz = 0;
490
491         res = rtw_enqueue_cmd(pcmdpriv, pcmd);
492
493 exit:
494
495         return res;
496 }
497
498 u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue) /* for sta_mode */
499 {
500         struct cmd_obj *cmdobj = NULL;
501         struct disconnect_parm *param = NULL;
502         struct cmd_priv *cmdpriv = &padapter->cmdpriv;
503         u8 res = _SUCCESS;
504
505         RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+%s\n", __func__));
506
507         /* prepare cmd parameter */
508         param = kzalloc(sizeof(*param), GFP_ATOMIC);
509         if (!param) {
510                 res = _FAIL;
511                 goto exit;
512         }
513         param->deauth_timeout_ms = deauth_timeout_ms;
514
515         if (enqueue) {
516                 /* need enqueue, prepare cmd_obj and enqueue */
517                 cmdobj = kzalloc(sizeof(*cmdobj), GFP_ATOMIC);
518                 if (!cmdobj) {
519                         res = _FAIL;
520                         kfree(param);
521                         goto exit;
522                 }
523                 init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_);
524                 res = rtw_enqueue_cmd(cmdpriv, cmdobj);
525         } else {
526                 /* no need to enqueue, do the cmd hdl directly and free cmd parameter */
527                 if (disconnect_hdl(padapter, (u8 *)param) != H2C_SUCCESS)
528                         res = _FAIL;
529                 kfree(param);
530         }
531
532 exit:
533
534         return res;
535 }
536
537 u8 rtw_setopmode_cmd(struct adapter  *padapter, enum ndis_802_11_network_infra networktype)
538 {
539         struct  cmd_obj *ph2c;
540         struct  setopmode_parm *psetop;
541
542         struct  cmd_priv   *pcmdpriv = &padapter->cmdpriv;
543
544         ph2c = kzalloc(sizeof(*ph2c), GFP_KERNEL);
545         psetop = kzalloc(sizeof(*psetop), GFP_KERNEL);
546         if (!ph2c || !psetop) {
547                 kfree(ph2c);
548                 kfree(psetop);
549                 return false;
550         }
551
552         init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
553         psetop->mode = (u8)networktype;
554
555         return rtw_enqueue_cmd(pcmdpriv, ph2c);
556 }
557
558 u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key)
559 {
560         struct cmd_obj *ph2c;
561         struct set_stakey_parm *psetstakey_para;
562         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
563         struct set_stakey_rsp *psetstakey_rsp = NULL;
564
565         struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
566         struct security_priv *psecuritypriv = &padapter->securitypriv;
567         struct sta_info *sta = (struct sta_info *)psta;
568
569         ph2c = kzalloc(sizeof(*ph2c), GFP_KERNEL);
570         psetstakey_para = kzalloc(sizeof(*psetstakey_para), GFP_KERNEL);
571         psetstakey_rsp = kzalloc(sizeof(*psetstakey_rsp), GFP_KERNEL);
572
573         if (!ph2c || !psetstakey_para || !psetstakey_rsp) {
574                 kfree(ph2c);
575                 kfree(psetstakey_para);
576                 kfree(psetstakey_rsp);
577                 return _FAIL;
578         }
579
580         init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
581         ph2c->rsp = (u8 *)psetstakey_rsp;
582         ph2c->rspsz = sizeof(struct set_stakey_rsp);
583
584         ether_addr_copy(psetstakey_para->addr, sta->hwaddr);
585
586         if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
587                 psetstakey_para->algorithm = (unsigned char)psecuritypriv->dot11PrivacyAlgrthm;
588         else
589                 GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, false);
590
591         if (unicast_key)
592                 memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16);
593         else
594                 memcpy(&psetstakey_para->key,
595                        &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16);
596
597         /* jeff: set this because at least sw key is ready */
598         padapter->securitypriv.busetkipkey = true;
599
600         return rtw_enqueue_cmd(pcmdpriv, ph2c);
601 }
602
603 u8 rtw_clearstakey_cmd(struct adapter *padapter, u8 *psta, u8 entry, u8 enqueue)
604 {
605         struct cmd_obj *ph2c;
606         struct set_stakey_parm  *psetstakey_para;
607         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
608         struct set_stakey_rsp *psetstakey_rsp = NULL;
609         struct sta_info *sta = (struct sta_info *)psta;
610         u8      res = _SUCCESS;
611
612         if (!enqueue) {
613                 clear_cam_entry(padapter, entry);
614         } else {
615                 ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
616                 if (!ph2c) {
617                         res = _FAIL;
618                         goto exit;
619                 }
620
621                 psetstakey_para = kzalloc(sizeof(*psetstakey_para), GFP_ATOMIC);
622                 if (!psetstakey_para) {
623                         kfree(ph2c);
624                         res = _FAIL;
625                         goto exit;
626                 }
627
628                 psetstakey_rsp = kzalloc(sizeof(*psetstakey_rsp), GFP_ATOMIC);
629                 if (!psetstakey_rsp) {
630                         kfree(ph2c);
631                         kfree(psetstakey_para);
632                         res = _FAIL;
633                         goto exit;
634                 }
635
636                 init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
637                 ph2c->rsp = (u8 *)psetstakey_rsp;
638                 ph2c->rspsz = sizeof(struct set_stakey_rsp);
639
640                 ether_addr_copy(psetstakey_para->addr, sta->hwaddr);
641
642                 psetstakey_para->algorithm = _NO_PRIVACY_;
643
644                 psetstakey_para->id = entry;
645
646                 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
647         }
648 exit:
649
650         return res;
651 }
652
653 u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr)
654 {
655         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
656         struct cmd_obj *ph2c;
657         struct addBaReq_parm *paddbareq_parm;
658         u8      res = _SUCCESS;
659
660         ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
661         if (!ph2c) {
662                 res = _FAIL;
663                 goto exit;
664         }
665
666         paddbareq_parm = kzalloc(sizeof(*paddbareq_parm), GFP_ATOMIC);
667         if (!paddbareq_parm) {
668                 kfree(ph2c);
669                 res = _FAIL;
670                 goto exit;
671         }
672
673         paddbareq_parm->tid = tid;
674         memcpy(paddbareq_parm->addr, addr, ETH_ALEN);
675
676         init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, _AddBAReq_CMD_);
677
678         res = rtw_enqueue_cmd(pcmdpriv, ph2c);
679
680 exit:
681
682         return res;
683 }
684
685 u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter)
686 {
687         struct cmd_obj *ph2c;
688         struct drvextra_cmd_parm *pdrvextra_cmd_parm;
689         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
690         u8      res = _SUCCESS;
691
692         ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
693         if (!ph2c) {
694                 res = _FAIL;
695                 goto exit;
696         }
697
698         pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
699         if (!pdrvextra_cmd_parm) {
700                 kfree(ph2c);
701                 res = _FAIL;
702                 goto exit;
703         }
704
705         pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID;
706         pdrvextra_cmd_parm->type_size = 0;
707         pdrvextra_cmd_parm->pbuf = (u8 *)padapter;
708
709         init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, _Set_Drv_Extra_CMD_);
710
711         res = rtw_enqueue_cmd(pcmdpriv, ph2c);
712 exit:
713         return res;
714 }
715
716 u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue)
717 {
718         struct  cmd_obj *pcmdobj;
719         struct  SetChannelPlan_param *setChannelPlan_param;
720         struct  cmd_priv   *pcmdpriv = &padapter->cmdpriv;
721
722         u8      res = _SUCCESS;
723
724         RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+%s\n", __func__));
725
726         /* check input parameter */
727         if (!rtw_is_channel_plan_valid(chplan)) {
728                 res = _FAIL;
729                 goto exit;
730         }
731
732         /* prepare cmd parameter */
733         setChannelPlan_param = kzalloc(sizeof(*setChannelPlan_param), GFP_KERNEL);
734         if (!setChannelPlan_param) {
735                 res = _FAIL;
736                 goto exit;
737         }
738         setChannelPlan_param->channel_plan = chplan;
739
740         if (enqueue) {
741                 /* need enqueue, prepare cmd_obj and enqueue */
742                 pcmdobj = kzalloc(sizeof(*pcmdobj), GFP_KERNEL);
743                 if (!pcmdobj) {
744                         kfree(setChannelPlan_param);
745                         res = _FAIL;
746                         goto exit;
747                 }
748
749                 init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelPlan_param, _SetChannelPlan_CMD_);
750                 res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
751         } else {
752                 /* no need to enqueue, do the cmd hdl directly and free cmd parameter */
753                 if (set_chplan_hdl(padapter, (unsigned char *)setChannelPlan_param) != H2C_SUCCESS)
754                         res = _FAIL;
755
756                 kfree(setChannelPlan_param);
757         }
758
759         if (res == _SUCCESS)
760                 padapter->mlmepriv.ChannelPlan = chplan;
761
762 exit:
763
764         return res;
765 }
766
767 static void traffic_status_watchdog(struct adapter *padapter)
768 {
769         u8      bEnterPS;
770         u8      bBusyTraffic = false, bTxBusyTraffic = false, bRxBusyTraffic = false;
771         u8      bHigherBusyTraffic = false, bHigherBusyRxTraffic = false, bHigherBusyTxTraffic = false;
772         struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
773
774         /*  */
775         /*  Determine if our traffic is busy now */
776         /*  */
777         if (check_fwstate(pmlmepriv, _FW_LINKED)) {
778                 if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 100 ||
779                     pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 100) {
780                         bBusyTraffic = true;
781
782                         if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod >
783                             pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
784                                 bRxBusyTraffic = true;
785                         else
786                                 bTxBusyTraffic = true;
787                 }
788
789                 /*  Higher Tx/Rx data. */
790                 if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 ||
791                     pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000) {
792                         bHigherBusyTraffic = true;
793
794                         if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod >
795                             pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
796                                 bHigherBusyRxTraffic = true;
797                         else
798                                 bHigherBusyTxTraffic = true;
799                 }
800
801                 /*  check traffic for  powersaving. */
802                 if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) ||
803                     (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2))
804                         bEnterPS = false;
805                 else
806                         bEnterPS = true;
807
808                 /*  LeisurePS only work in infra mode. */
809                 if (bEnterPS)
810                         LPS_Enter(padapter);
811                 else
812                         LPS_Leave(padapter);
813         } else {
814                 LPS_Leave(padapter);
815         }
816
817         pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0;
818         pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0;
819         pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0;
820         pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic;
821         pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic;
822         pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic;
823         pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic;
824         pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic;
825         pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic;
826 }
827
828 static void dynamic_chk_wk_hdl(struct adapter *padapter, u8 *pbuf, int sz)
829 {
830         struct mlme_priv *pmlmepriv;
831
832         padapter = (struct adapter *)pbuf;
833         pmlmepriv = &padapter->mlmepriv;
834
835 #ifdef CONFIG_88EU_AP_MODE
836         if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
837                 expire_timeout_chk(padapter);
838 #endif
839
840         linked_status_chk(padapter);
841         traffic_status_watchdog(padapter);
842
843         rtw_hal_dm_watchdog(padapter);
844 }
845
846 static void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type)
847 {
848         struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
849         struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
850         u8      mstatus;
851
852         if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ||
853             check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))
854                 return;
855
856         switch (lps_ctrl_type) {
857         case LPS_CTRL_SCAN:
858                 if (check_fwstate(pmlmepriv, _FW_LINKED)) {
859                         /* connect */
860                         LPS_Leave(padapter);
861                 }
862                 break;
863         case LPS_CTRL_JOINBSS:
864                 LPS_Leave(padapter);
865                 break;
866         case LPS_CTRL_CONNECT:
867                 mstatus = 1;/* connect */
868                 /*  Reset LPS Setting */
869                 padapter->pwrctrlpriv.LpsIdleCount = 0;
870                 rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
871                 break;
872         case LPS_CTRL_DISCONNECT:
873                 mstatus = 0;/* disconnect */
874                 LPS_Leave(padapter);
875                 rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
876                 break;
877         case LPS_CTRL_SPECIAL_PACKET:
878                 pwrpriv->DelayLPSLastTimeStamp = jiffies;
879                 LPS_Leave(padapter);
880                 break;
881         case LPS_CTRL_LEAVE:
882                 LPS_Leave(padapter);
883                 break;
884         default:
885                 break;
886         }
887 }
888
889 u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue)
890 {
891         struct cmd_obj  *ph2c;
892         struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
893         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
894         u8      res = _SUCCESS;
895
896         if (enqueue) {
897                 ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
898                 if (!ph2c) {
899                         res = _FAIL;
900                         goto exit;
901                 }
902
903                 pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
904                 if (!pdrvextra_cmd_parm) {
905                         kfree(ph2c);
906                         res = _FAIL;
907                         goto exit;
908                 }
909
910                 pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID;
911                 pdrvextra_cmd_parm->type_size = lps_ctrl_type;
912                 pdrvextra_cmd_parm->pbuf = NULL;
913
914                 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, _Set_Drv_Extra_CMD_);
915
916                 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
917         } else {
918                 lps_ctrl_wk_hdl(padapter, lps_ctrl_type);
919         }
920
921 exit:
922
923         return res;
924 }
925
926 static void rpt_timer_setting_wk_hdl(struct adapter *padapter, u16 min_time)
927 {
928         rtw_hal_set_hwreg(padapter, HW_VAR_RPT_TIMER_SETTING, (u8 *)(&min_time));
929 }
930
931 u8 rtw_rpt_timer_cfg_cmd(struct adapter *padapter, u16 min_time)
932 {
933         struct cmd_obj          *ph2c;
934         struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
935         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
936
937         u8      res = _SUCCESS;
938
939         ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
940         if (!ph2c) {
941                 res = _FAIL;
942                 goto exit;
943         }
944
945         pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
946         if (!pdrvextra_cmd_parm) {
947                 kfree(ph2c);
948                 res = _FAIL;
949                 goto exit;
950         }
951
952         pdrvextra_cmd_parm->ec_id = RTP_TIMER_CFG_WK_CID;
953         pdrvextra_cmd_parm->type_size = min_time;
954         pdrvextra_cmd_parm->pbuf = NULL;
955         init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, _Set_Drv_Extra_CMD_);
956         res = rtw_enqueue_cmd(pcmdpriv, ph2c);
957 exit:
958
959         return res;
960 }
961
962 static void antenna_select_wk_hdl(struct adapter *padapter, u8 antenna)
963 {
964         rtw_hal_set_hwreg(padapter, HW_VAR_ANTENNA_DIVERSITY_SELECT, (u8 *)(&antenna));
965 }
966
967 u8 rtw_antenna_select_cmd(struct adapter *padapter, u8 antenna, u8 enqueue)
968 {
969         struct cmd_obj          *ph2c;
970         struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
971         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
972         u8      support_ant_div;
973         u8      res = _SUCCESS;
974
975         rtw_hal_get_def_var(padapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &support_ant_div);
976         if (!support_ant_div)
977                 return res;
978
979         if (enqueue) {
980                 ph2c = kzalloc(sizeof(*ph2c), GFP_KERNEL);
981                 if (!ph2c) {
982                         res = _FAIL;
983                         goto exit;
984                 }
985
986                 pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_KERNEL);
987                 if (!pdrvextra_cmd_parm) {
988                         kfree(ph2c);
989                         res = _FAIL;
990                         goto exit;
991                 }
992
993                 pdrvextra_cmd_parm->ec_id = ANT_SELECT_WK_CID;
994                 pdrvextra_cmd_parm->type_size = antenna;
995                 pdrvextra_cmd_parm->pbuf = NULL;
996                 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, _Set_Drv_Extra_CMD_);
997
998                 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
999         } else {
1000                 antenna_select_wk_hdl(padapter, antenna);
1001         }
1002 exit:
1003
1004         return res;
1005 }
1006
1007 u8 rtw_ps_cmd(struct adapter *padapter)
1008 {
1009         struct cmd_obj          *ppscmd;
1010         struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
1011         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1012
1013         ppscmd = kzalloc(sizeof(*ppscmd), GFP_ATOMIC);
1014         pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
1015         if (!ppscmd || !pdrvextra_cmd_parm) {
1016                 kfree(ppscmd);
1017                 kfree(pdrvextra_cmd_parm);
1018                 return _FAIL;
1019         }
1020
1021         pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID;
1022         pdrvextra_cmd_parm->pbuf = NULL;
1023         init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, _Set_Drv_Extra_CMD_);
1024
1025         return rtw_enqueue_cmd(pcmdpriv, ppscmd);
1026 }
1027
1028 #ifdef CONFIG_88EU_AP_MODE
1029
1030 static void rtw_chk_hi_queue_hdl(struct adapter *padapter)
1031 {
1032         int cnt = 0;
1033         struct sta_info *psta_bmc;
1034         struct sta_priv *pstapriv = &padapter->stapriv;
1035
1036         psta_bmc = rtw_get_bcmc_stainfo(padapter);
1037         if (!psta_bmc)
1038                 return;
1039
1040         if (psta_bmc->sleepq_len == 0) {
1041                 u8 val = 0;
1042
1043                 rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val);
1044
1045                 while (!val) {
1046                         msleep(100);
1047
1048                         cnt++;
1049
1050                         if (cnt > 10)
1051                                 break;
1052
1053                         rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val);
1054                 }
1055
1056                 if (cnt <= 10) {
1057                         pstapriv->tim_bitmap &= ~BIT(0);
1058                         pstapriv->sta_dz_bitmap &= ~BIT(0);
1059
1060                         update_beacon(padapter, _TIM_IE_, NULL, false);
1061                 } else { /* re check again */
1062                         rtw_chk_hi_queue_cmd(padapter);
1063                 }
1064         }
1065 }
1066
1067 u8 rtw_chk_hi_queue_cmd(struct adapter *padapter)
1068 {
1069         struct cmd_obj  *ph2c;
1070         struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
1071         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1072         u8      res = _SUCCESS;
1073
1074         ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
1075         if (!ph2c) {
1076                 res = _FAIL;
1077                 goto exit;
1078         }
1079
1080         pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
1081         if (!pdrvextra_cmd_parm) {
1082                 kfree(ph2c);
1083                 res = _FAIL;
1084                 goto exit;
1085         }
1086
1087         pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID;
1088         pdrvextra_cmd_parm->type_size = 0;
1089         pdrvextra_cmd_parm->pbuf = NULL;
1090
1091         init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, _Set_Drv_Extra_CMD_);
1092
1093         res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1094 exit:
1095         return res;
1096 }
1097 #endif
1098
1099 u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf)
1100 {
1101         struct drvextra_cmd_parm *pdrvextra_cmd;
1102
1103         if (!pbuf)
1104                 return H2C_PARAMETERS_ERROR;
1105
1106         pdrvextra_cmd = (struct drvextra_cmd_parm *)pbuf;
1107
1108         switch (pdrvextra_cmd->ec_id) {
1109         case DYNAMIC_CHK_WK_CID:
1110                 dynamic_chk_wk_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size);
1111                 break;
1112         case POWER_SAVING_CTRL_WK_CID:
1113                 rtw_ps_processor(padapter);
1114                 break;
1115         case LPS_CTRL_WK_CID:
1116                 lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type_size);
1117                 break;
1118         case RTP_TIMER_CFG_WK_CID:
1119                 rpt_timer_setting_wk_hdl(padapter, pdrvextra_cmd->type_size);
1120                 break;
1121         case ANT_SELECT_WK_CID:
1122                 antenna_select_wk_hdl(padapter, pdrvextra_cmd->type_size);
1123                 break;
1124 #ifdef CONFIG_88EU_AP_MODE
1125         case CHECK_HIQ_WK_CID:
1126                 rtw_chk_hi_queue_hdl(padapter);
1127                 break;
1128 #endif /* CONFIG_88EU_AP_MODE */
1129         default:
1130                 break;
1131         }
1132
1133         if (pdrvextra_cmd->pbuf && pdrvextra_cmd->type_size > 0)
1134                 kfree(pdrvextra_cmd->pbuf);
1135
1136         return H2C_SUCCESS;
1137 }
1138
1139 void rtw_survey_cmd_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
1140 {
1141         struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
1142
1143         if (pcmd->res == H2C_DROPPED) {
1144                 /* TODO: cancel timer and do timeout handler directly... */
1145                 /* need to make timeout handlerOS independent */
1146                 mod_timer(&pmlmepriv->scan_to_timer,
1147                           jiffies + msecs_to_jiffies(1));
1148         } else if (pcmd->res != H2C_SUCCESS) {
1149                 mod_timer(&pmlmepriv->scan_to_timer,
1150                           jiffies + msecs_to_jiffies(1));
1151                 RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
1152                          ("\n ********Error: MgntActrtw_set_802_11_bssid_LIST_SCAN Fail ************\n\n."));
1153         }
1154
1155         /*  free cmd */
1156         rtw_free_cmd_obj(pcmd);
1157 }
1158
1159 void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
1160 {
1161         struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
1162
1163         if (pcmd->res != H2C_SUCCESS) {
1164                 spin_lock_bh(&pmlmepriv->lock);
1165                 set_fwstate(pmlmepriv, _FW_LINKED);
1166                 spin_unlock_bh(&pmlmepriv->lock);
1167
1168                 RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
1169                          ("\n ***Error: disconnect_cmd_callback Fail ***\n."));
1170                 return;
1171         }
1172
1173         /*  free cmd */
1174         rtw_free_cmd_obj(pcmd);
1175 }
1176
1177 void rtw_joinbss_cmd_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
1178 {
1179         struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
1180
1181         if (pcmd->res == H2C_DROPPED) {
1182                 /* TODO: cancel timer and do timeout handler directly... */
1183                 /* need to make timeout handlerOS independent */
1184                 mod_timer(&pmlmepriv->assoc_timer,
1185                           jiffies + msecs_to_jiffies(1));
1186         } else if (pcmd->res != H2C_SUCCESS) {
1187                 RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
1188                          ("********Error:rtw_select_and_join_from_scanned_queue Wait Sema  Fail ************\n"));
1189                 mod_timer(&pmlmepriv->assoc_timer,
1190                           jiffies + msecs_to_jiffies(1));
1191         }
1192
1193         rtw_free_cmd_obj(pcmd);
1194 }
1195
1196 void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
1197 {
1198         struct sta_info *psta = NULL;
1199         struct wlan_network *pwlan = NULL;
1200         struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
1201         struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf;
1202         struct wlan_network *tgt_network = &pmlmepriv->cur_network;
1203
1204         if (pcmd->res != H2C_SUCCESS) {
1205                 RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
1206                          ("\n **** Error: %s  Fail ****\n\n.", __func__));
1207                 mod_timer(&pmlmepriv->assoc_timer,
1208                           jiffies + msecs_to_jiffies(1));
1209         }
1210
1211         del_timer_sync(&pmlmepriv->assoc_timer);
1212
1213         spin_lock_bh(&pmlmepriv->lock);
1214
1215         if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
1216                 psta = rtw_get_stainfo(&padapter->stapriv, pnetwork->MacAddress);
1217                 if (!psta) {
1218                         psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress);
1219                         if (!psta) {
1220                                 RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
1221                                          ("\nCan't alloc sta_info when createbss_cmd_callback\n"));
1222                                 goto createbss_cmd_fail;
1223                         }
1224                 }
1225
1226                 rtw_indicate_connect(padapter);
1227         } else {
1228                 pwlan = rtw_alloc_network(pmlmepriv);
1229                 spin_lock_bh(&pmlmepriv->scanned_queue.lock);
1230                 if (!pwlan) {
1231                         pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue);
1232                         if (!pwlan) {
1233                                 RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
1234                                          ("\n Error:  can't get pwlan in rtw_joinbss_event_callback\n"));
1235                                 spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
1236                                 goto createbss_cmd_fail;
1237                         }
1238                         pwlan->last_scanned = jiffies;
1239                 } else {
1240                         list_add_tail(&pwlan->list,
1241                                       &pmlmepriv->scanned_queue.queue);
1242                 }
1243
1244                 pnetwork->Length = get_wlan_bssid_ex_sz(pnetwork);
1245                 memcpy(&pwlan->network, pnetwork, pnetwork->Length);
1246
1247                 memcpy(&tgt_network->network, pnetwork, (get_wlan_bssid_ex_sz(pnetwork)));
1248
1249                 _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
1250
1251                 spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
1252                 /*  we will set _FW_LINKED when there is one more sat to
1253                  *  join us (rtw_stassoc_event_callback)
1254                  */
1255         }
1256
1257 createbss_cmd_fail:
1258
1259         spin_unlock_bh(&pmlmepriv->lock);
1260
1261         rtw_free_cmd_obj(pcmd);
1262 }
1263
1264 void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
1265 {
1266         struct sta_priv *pstapriv = &padapter->stapriv;
1267         struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *)(pcmd->rsp);
1268         struct sta_info *psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr);
1269
1270         if (!psta) {
1271                 RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
1272                          ("\nERROR: %s => can't get sta_info\n\n", __func__));
1273                 goto exit;
1274         }
1275 exit:
1276         rtw_free_cmd_obj(pcmd);
1277 }
1278
1279 void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
1280 {
1281         struct sta_priv *pstapriv = &padapter->stapriv;
1282         struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1283         struct set_assocsta_parm *passocsta_parm = (struct set_assocsta_parm *)(pcmd->parmbuf);
1284         struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *)(pcmd->rsp);
1285         struct sta_info *psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr);
1286
1287         if (!psta) {
1288                 RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
1289                          ("\nERROR: %s => can't get sta_info\n\n", __func__));
1290                 goto exit;
1291         }
1292
1293         psta->aid = passocsta_rsp->cam_id;
1294         psta->mac_id = passocsta_rsp->cam_id;
1295
1296         spin_lock_bh(&pmlmepriv->lock);
1297
1298         set_fwstate(pmlmepriv, _FW_LINKED);
1299         spin_unlock_bh(&pmlmepriv->lock);
1300
1301 exit:
1302         rtw_free_cmd_obj(pcmd);
1303 }