1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2007 - 2012 Realtek Corporation. */
3
4 #define _RTW_CMD_C_
5
6 #include "../include/osdep_service.h"
7 #include "../include/drv_types.h"
8 #include "../include/recv_osdep.h"
9 #include "../include/mlme_osdep.h"
10 #include "../include/rtw_br_ext.h"
11 #include "../include/rtw_mlme_ext.h"
12 #include "../include/rtl8188e_dm.h"
13
14 /* Caller and the rtw_cmd_thread can protect cmd_q by spin_lock.
15 * No irqsave is necessary.
16 */
17
18 static void c2h_wk_callback(struct work_struct *work);
19
rtw_free_evt_priv(struct evt_priv * pevtpriv)20 void rtw_free_evt_priv(struct evt_priv *pevtpriv)
21 {
22 cancel_work_sync(&pevtpriv->c2h_wk);
23 while (pevtpriv->c2h_wk_alive)
24 msleep(10);
25
26 while (!rtw_cbuf_empty(pevtpriv->c2h_queue)) {
27 void *c2h = rtw_cbuf_pop(pevtpriv->c2h_queue);
28 if (c2h && c2h != (void *)pevtpriv)
29 kfree(c2h);
30 }
31 }
32
33 /* Calling Context:
34 *
35 * rtw_enqueue_cmd can only be called between kernel thread,
36 * since only spin_lock is used.
37 *
38 * ISR/Call-Back functions can't call this sub-function.
39 */
40
_rtw_enqueue_cmd(struct __queue * queue,struct cmd_obj * obj)41 static int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj)
42 {
43 unsigned long flags;
44
45 if (!obj)
46 goto exit;
47
48 spin_lock_irqsave(&queue->lock, flags);
49
50 list_add_tail(&obj->list, &queue->queue);
51
52 spin_unlock_irqrestore(&queue->lock, flags);
53
54 exit:
55
56 return _SUCCESS;
57 }
58
rtw_init_cmd_priv(struct cmd_priv * pcmdpriv)59 u32 rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
60 {
61 u32 res = _SUCCESS;
62
63 init_completion(&pcmdpriv->enqueue_cmd);
64 /* sema_init(&(pcmdpriv->cmd_done_sema), 0); */
65 init_completion(&pcmdpriv->start_cmd_thread);
66 init_completion(&pcmdpriv->stop_cmd_thread);
67
68 rtw_init_queue(&pcmdpriv->cmd_queue);
69
70 /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
71
72 pcmdpriv->cmd_seq = 1;
73
74 pcmdpriv->cmd_allocated_buf = kzalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ,
75 GFP_KERNEL);
76
77 if (!pcmdpriv->cmd_allocated_buf) {
78 res = _FAIL;
79 goto exit;
80 }
81
82 pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf + CMDBUFF_ALIGN_SZ - ((size_t)(pcmdpriv->cmd_allocated_buf) & (CMDBUFF_ALIGN_SZ - 1));
83
84 pcmdpriv->rsp_allocated_buf = kzalloc(MAX_RSPSZ + 4, GFP_KERNEL);
85
86 if (!pcmdpriv->rsp_allocated_buf) {
87 res = _FAIL;
88 goto exit;
89 }
90
91 pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf + 4 - ((size_t)(pcmdpriv->rsp_allocated_buf) & 3);
92
93 pcmdpriv->cmd_done_cnt = 0;
94 pcmdpriv->rsp_cnt = 0;
95 exit:
96
97 return res;
98 }
99
rtw_init_evt_priv(struct evt_priv * pevtpriv)100 u32 rtw_init_evt_priv(struct evt_priv *pevtpriv)
101 {
102 u32 res = _SUCCESS;
103
104 /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
105 atomic_set(&pevtpriv->event_seq, 0);
106
107 INIT_WORK(&pevtpriv->c2h_wk, c2h_wk_callback);
108 pevtpriv->c2h_wk_alive = false;
109 pevtpriv->c2h_queue = rtw_cbuf_alloc(C2H_QUEUE_MAX_LEN + 1);
110 if (!pevtpriv->c2h_queue)
111 res = _FAIL;
112
113 return res;
114 }
115
rtw_free_cmd_priv(struct cmd_priv * pcmdpriv)116 void rtw_free_cmd_priv(struct cmd_priv *pcmdpriv)
117 {
118 if (pcmdpriv) {
119 kfree(pcmdpriv->cmd_allocated_buf);
120 kfree(pcmdpriv->rsp_allocated_buf);
121 }
122 }
123
rtw_cmd_filter(struct cmd_priv * pcmdpriv,struct cmd_obj * cmd_obj)124 static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
125 {
126 u8 bAllow = false; /* set to true to allow enqueuing cmd when hw_init_completed is false */
127
128 if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan))
129 bAllow = true;
130
131 if ((!pcmdpriv->padapter->hw_init_completed && !bAllow) ||
132 !pcmdpriv->cmdthd_running) /* com_thread not running */
133 return _FAIL;
134 return _SUCCESS;
135 }
136
rtw_enqueue_cmd(struct cmd_priv * pcmdpriv,struct cmd_obj * cmd_obj)137 u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
138 {
139 int res = _FAIL;
140 struct adapter *padapter = pcmdpriv->padapter;
141
142 if (!cmd_obj)
143 goto exit;
144
145 cmd_obj->padapter = padapter;
146
147 res = rtw_cmd_filter(pcmdpriv, cmd_obj);
148 if (res == _FAIL) {
149 rtw_free_cmd_obj(cmd_obj);
150 goto exit;
151 }
152
153 res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj);
154
155 if (res == _SUCCESS)
156 complete(&pcmdpriv->enqueue_cmd);
157
158 exit:
159
160 return res;
161 }
162
rtw_dequeue_cmd(struct cmd_priv * pcmdpriv)163 struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv)
164 {
165 struct cmd_obj *obj;
166 struct __queue *queue = &pcmdpriv->cmd_queue;
167 unsigned long flags;
168
169 spin_lock_irqsave(&queue->lock, flags);
170 if (list_empty(&queue->queue)) {
171 obj = NULL;
172 } else {
173 obj = container_of((&queue->queue)->next, struct cmd_obj, list);
174 list_del_init(&obj->list);
175 }
176
177 spin_unlock_irqrestore(&queue->lock, flags);
178
179 return obj;
180 }
181
rtw_free_cmd_obj(struct cmd_obj * pcmd)182 void rtw_free_cmd_obj(struct cmd_obj *pcmd)
183 {
184
185 if ((pcmd->cmdcode != _JoinBss_CMD_) && (pcmd->cmdcode != _CreateBss_CMD_)) {
186 /* free parmbuf in cmd_obj */
187 kfree(pcmd->parmbuf);
188 }
189
190 if (pcmd->rsp) {
191 if (pcmd->rspsz != 0) {
192 /* free rsp in cmd_obj */
193 kfree(pcmd->rsp);
194 }
195 }
196
197 /* free cmd_obj */
198 kfree(pcmd);
199
200 }
201
rtw_cmd_thread(void * context)202 int rtw_cmd_thread(void *context)
203 {
204 u8 ret;
205 struct cmd_obj *pcmd;
206 u8 *pcmdbuf;
207 u8 (*cmd_hdl)(struct adapter *padapter, u8 *pbuf);
208 void (*pcmd_callback)(struct adapter *dev, struct cmd_obj *pcmd);
209 struct adapter *padapter = (struct adapter *)context;
210 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
211
212 pcmdbuf = pcmdpriv->cmd_buf;
213
214 pcmdpriv->cmdthd_running = true;
215 complete(&pcmdpriv->start_cmd_thread);
216
217 while (1) {
218 wait_for_completion(&pcmdpriv->enqueue_cmd);
219
220 _next:
221 if (padapter->bDriverStopped ||
222 padapter->bSurpriseRemoved)
223 break;
224
225 pcmd = rtw_dequeue_cmd(pcmdpriv);
226 if (!pcmd)
227 continue;
228
229 if (rtw_cmd_filter(pcmdpriv, pcmd) == _FAIL) {
230 pcmd->res = H2C_DROPPED;
231 goto post_process;
232 }
233
234 pcmd->cmdsz = round_up(pcmd->cmdsz, 4);
235
236 memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz);
237
238 if (pcmd->cmdcode < ARRAY_SIZE(wlancmds)) {
239 cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns;
240
241 if (cmd_hdl) {
242 ret = cmd_hdl(pcmd->padapter, pcmdbuf);
243 pcmd->res = ret;
244 }
245
246 pcmdpriv->cmd_seq++;
247 } else {
248 pcmd->res = H2C_PARAMETERS_ERROR;
249 }
250
251 cmd_hdl = NULL;
252
253 post_process:
254
255 /* call callback function for post-processed */
256 if (pcmd->cmdcode < ARRAY_SIZE(rtw_cmd_callback)) {
257 pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback;
258 if (!pcmd_callback)
259 rtw_free_cmd_obj(pcmd);
260 else
261 /* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */
262 pcmd_callback(pcmd->padapter, pcmd);/* need consider that free cmd_obj in rtw_cmd_callback */
263 } else {
264 rtw_free_cmd_obj(pcmd);
265 }
266
267 flush_signals_thread();
268
269 goto _next;
270 }
271 pcmdpriv->cmdthd_running = false;
272
273 /* free all cmd_obj resources */
274 do {
275 pcmd = rtw_dequeue_cmd(pcmdpriv);
276 if (!pcmd)
277 break;
278
279 rtw_free_cmd_obj(pcmd);
280 } while (1);
281
282 complete(&pcmdpriv->stop_cmd_thread);
283
284 return 0;
285 }
286
287 /* rtw_sitesurvey_cmd(~)
288 * ### NOTE:#### (!!!!)
289 * MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock
290 */
rtw_sitesurvey_cmd(struct adapter * padapter,struct ndis_802_11_ssid * ssid,int ssid_num,struct rtw_ieee80211_channel * ch,int ch_num)291 u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid, int ssid_num,
292 struct rtw_ieee80211_channel *ch, int ch_num)
293 {
294 u8 res = _FAIL;
295 struct cmd_obj *ph2c;
296 struct sitesurvey_parm *psurveyPara;
297 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
298 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
299
300 if (check_fwstate(pmlmepriv, _FW_LINKED))
301 rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1);
302
303 if (check_fwstate(pmlmepriv, _FW_LINKED))
304 p2p_ps_wk_cmd(padapter, P2P_PS_SCAN, 1);
305
306 ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
307 if (!ph2c)
308 return _FAIL;
309
310 psurveyPara = kzalloc(sizeof(*psurveyPara), GFP_ATOMIC);
311 if (!psurveyPara) {
312 kfree(ph2c);
313 return _FAIL;
314 }
315
316 rtw_free_network_queue(padapter, false);
317
318 init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey));
319
320 /* psurveyPara->bsslimit = 48; */
321 psurveyPara->scan_mode = pmlmepriv->scan_mode;
322
323 /* prepare ssid list */
324 if (ssid) {
325 int i;
326 for (i = 0; i < ssid_num && i < RTW_SSID_SCAN_AMOUNT; i++) {
327 if (ssid[i].SsidLength) {
328 memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(struct ndis_802_11_ssid));
329 psurveyPara->ssid_num++;
330 }
331 }
332 }
333
334 /* prepare channel list */
335 if (ch) {
336 int i;
337 for (i = 0; i < ch_num && i < RTW_CHANNEL_SCAN_AMOUNT; i++) {
338 if (ch[i].hw_value && !(ch[i].flags & RTW_IEEE80211_CHAN_DISABLED)) {
339 memcpy(&psurveyPara->ch[i], &ch[i], sizeof(struct rtw_ieee80211_channel));
340 psurveyPara->ch_num++;
341 }
342 }
343 }
344
345 set_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
346
347 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
348
349 if (res == _SUCCESS) {
350 pmlmepriv->scan_start_time = jiffies;
351
352 _set_timer(&pmlmepriv->scan_to_timer, SCANNING_TIMEOUT);
353
354 rtw_led_control(padapter, LED_CTL_SITE_SURVEY);
355
356 pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */
357 } else {
358 _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
359 }
360
361 return res;
362 }
363
rtw_setdatarate_cmd(struct adapter * padapter,u8 * rateset)364 u8 rtw_setdatarate_cmd(struct adapter *padapter, u8 *rateset)
365 {
366 struct cmd_obj *ph2c;
367 struct setdatarate_parm *pbsetdataratepara;
368 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
369 u8 res = _SUCCESS;
370
371 ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
372 if (!ph2c) {
373 res = _FAIL;
374 goto exit;
375 }
376
377 pbsetdataratepara = kzalloc(sizeof(*pbsetdataratepara), GFP_ATOMIC);
378 if (!pbsetdataratepara) {
379 kfree(ph2c);
380 res = _FAIL;
381 goto exit;
382 }
383
384 init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara, GEN_CMD_CODE(_SetDataRate));
385 pbsetdataratepara->mac_id = 5;
386 memcpy(pbsetdataratepara->datarates, rateset, NumRates);
387 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
388 exit:
389
390 return res;
391 }
392
rtw_getbbrfreg_cmdrsp_callback(struct adapter * padapter,struct cmd_obj * pcmd)393 void rtw_getbbrfreg_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
394 {
395
396
397 kfree(pcmd->parmbuf);
398 kfree(pcmd);
399 }
400
rtw_createbss_cmd(struct adapter * padapter)401 u8 rtw_createbss_cmd(struct adapter *padapter)
402 {
403 struct cmd_obj *pcmd;
404 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
405 struct wlan_bssid_ex *pdev_network = &padapter->registrypriv.dev_network;
406 u8 res = _SUCCESS;
407
408 rtw_led_control(padapter, LED_CTL_START_TO_LINK);
409
410 pcmd = kzalloc(sizeof(*pcmd), GFP_ATOMIC);
411 if (!pcmd) {
412 res = _FAIL;
413 goto exit;
414 }
415
416 INIT_LIST_HEAD(&pcmd->list);
417 pcmd->cmdcode = _CreateBss_CMD_;
418 pcmd->parmbuf = (unsigned char *)pdev_network;
419 pcmd->cmdsz = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network);
420 pcmd->rsp = NULL;
421 pcmd->rspsz = 0;
422 pdev_network->Length = pcmd->cmdsz;
423 res = rtw_enqueue_cmd(pcmdpriv, pcmd);
424 exit:
425
426 return res;
427 }
428
rtw_joinbss_cmd(struct adapter * padapter,struct wlan_network * pnetwork)429 u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork)
430 {
431 u8 res = _SUCCESS;
432 uint t_len = 0;
433 struct wlan_bssid_ex *psecnetwork;
434 struct cmd_obj *pcmd;
435 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
436 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
437 struct qos_priv *pqospriv = &pmlmepriv->qospriv;
438 struct security_priv *psecuritypriv = &padapter->securitypriv;
439 struct registry_priv *pregistrypriv = &padapter->registrypriv;
440 struct ht_priv *phtpriv = &pmlmepriv->htpriv;
441 enum ndis_802_11_network_infra ndis_network_mode = pnetwork->network.InfrastructureMode;
442 struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
443 struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
444
445 rtw_led_control(padapter, LED_CTL_START_TO_LINK);
446
447 pcmd = kzalloc(sizeof(*pcmd), GFP_ATOMIC);
448 if (!pcmd) {
449 res = _FAIL;
450 goto exit;
451 }
452 /* for IEs is fix buf size */
453 t_len = sizeof(struct wlan_bssid_ex);
454
455 /* for hidden ap to set fw_state here */
456 if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE)) {
457 switch (ndis_network_mode) {
458 case Ndis802_11IBSS:
459 set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
460 break;
461 case Ndis802_11Infrastructure:
462 set_fwstate(pmlmepriv, WIFI_STATION_STATE);
463 break;
464 case Ndis802_11APMode:
465 case Ndis802_11AutoUnknown:
466 case Ndis802_11InfrastructureMax:
467 break;
468 }
469 }
470
471 psecnetwork = (struct wlan_bssid_ex *)&psecuritypriv->sec_bss;
472 if (!psecnetwork) {
473 kfree(pcmd);
474 res = _FAIL;
475 goto exit;
476 }
477
478 memset(psecnetwork, 0, t_len);
479
480 memcpy(psecnetwork, &pnetwork->network, get_wlan_bssid_ex_sz(&pnetwork->network));
481
482 psecuritypriv->authenticator_ie[0] = (unsigned char)psecnetwork->IELength;
483
484 if (psecnetwork->IELength - 12 < 255)
485 memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], psecnetwork->IELength - 12);
486 else
487 memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], 255);
488
489 psecnetwork->IELength = 0;
490 /* Added by Albert 2009/02/18 */
491 /* If the driver wants to use the bssid to create the connection. */
492 /* If not, we have to copy the connecting AP's MAC address to it so that */
493 /* the driver just has the bssid information for PMKIDList searching. */
494
495 if (!pmlmepriv->assoc_by_bssid)
496 memcpy(&pmlmepriv->assoc_bssid[0], &pnetwork->network.MacAddress[0], ETH_ALEN);
497
498 psecnetwork->IELength = rtw_restruct_sec_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength);
499
500 pqospriv->qos_option = 0;
501
502 if (pregistrypriv->wmm_enable) {
503 u32 tmp_len;
504
505 tmp_len = rtw_restruct_wmm_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength, psecnetwork->IELength);
506
507 if (psecnetwork->IELength != tmp_len) {
508 psecnetwork->IELength = tmp_len;
509 pqospriv->qos_option = 1; /* There is WMM IE in this corresp. beacon */
510 } else {
511 pqospriv->qos_option = 0;/* There is no WMM IE in this corresp. beacon */
512 }
513 }
514
515 phtpriv->ht_option = false;
516 if (pregistrypriv->ht_enable) {
517 /* Added by Albert 2010/06/23 */
518 /* For the WEP mode, we will use the bg mode to do the connection to avoid some IOT issue. */
519 /* Especially for Realtek 8192u SoftAP. */
520 if ((padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_) &&
521 (padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_) &&
522 (padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_)) {
523 /* rtw_restructure_ht_ie */
524 rtw_restructure_ht_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0],
525 pnetwork->network.IELength, &psecnetwork->IELength);
526 }
527 }
528
529 pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->network.IEs, pnetwork->network.IELength);
530
531 if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_TENDA)
532 padapter->pwrctrlpriv.smart_ps = 0;
533 else
534 padapter->pwrctrlpriv.smart_ps = padapter->registrypriv.smart_ps;
535
536 pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork);/* get cmdsz before endian conversion */
537
538 INIT_LIST_HEAD(&pcmd->list);
539 pcmd->cmdcode = _JoinBss_CMD_;/* GEN_CMD_CODE(_JoinBss) */
540 pcmd->parmbuf = (unsigned char *)psecnetwork;
541 pcmd->rsp = NULL;
542 pcmd->rspsz = 0;
543
544 res = rtw_enqueue_cmd(pcmdpriv, pcmd);
545
546 exit:
547
548 return res;
549 }
550
rtw_disassoc_cmd(struct adapter * padapter,u32 deauth_timeout_ms,bool enqueue)551 u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue) /* for sta_mode */
552 {
553 struct cmd_obj *cmdobj = NULL;
554 struct disconnect_parm *param = NULL;
555 struct cmd_priv *cmdpriv = &padapter->cmdpriv;
556 u8 res = _SUCCESS;
557
558 /* prepare cmd parameter */
559 param = kzalloc(sizeof(*param), GFP_ATOMIC);
560 if (!param) {
561 res = _FAIL;
562 goto exit;
563 }
564 param->deauth_timeout_ms = deauth_timeout_ms;
565
566 if (enqueue) {
567 /* need enqueue, prepare cmd_obj and enqueue */
568 cmdobj = kzalloc(sizeof(*cmdobj), GFP_ATOMIC);
569 if (!cmdobj) {
570 res = _FAIL;
571 kfree(param);
572 goto exit;
573 }
574 init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_);
575 res = rtw_enqueue_cmd(cmdpriv, cmdobj);
576 } else {
577 /* no need to enqueue, do the cmd hdl directly and free cmd parameter */
578 if (disconnect_hdl(padapter, (u8 *)param) != H2C_SUCCESS)
579 res = _FAIL;
580 kfree(param);
581 }
582
583 exit:
584
585 return res;
586 }
587
rtw_setopmode_cmd(struct adapter * padapter,enum ndis_802_11_network_infra networktype)588 u8 rtw_setopmode_cmd(struct adapter *padapter, enum ndis_802_11_network_infra networktype)
589 {
590 struct cmd_obj *ph2c;
591 struct setopmode_parm *psetop;
592
593 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
594 u8 res = _SUCCESS;
595
596 ph2c = kzalloc(sizeof(*ph2c), GFP_KERNEL);
597 if (!ph2c) {
598 res = false;
599 goto exit;
600 }
601 psetop = kzalloc(sizeof(*psetop), GFP_KERNEL);
602
603 if (!psetop) {
604 kfree(ph2c);
605 res = false;
606 goto exit;
607 }
608
609 init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
610 psetop->mode = (u8)networktype;
611
612 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
613
614 exit:
615
616 return res;
617 }
618
rtw_setstakey_cmd(struct adapter * padapter,u8 * psta,u8 unicast_key)619 u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key)
620 {
621 struct cmd_obj *ph2c;
622 struct set_stakey_parm *psetstakey_para;
623 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
624 struct set_stakey_rsp *psetstakey_rsp = NULL;
625
626 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
627 struct security_priv *psecuritypriv = &padapter->securitypriv;
628 struct sta_info *sta = (struct sta_info *)psta;
629 u8 res = _SUCCESS;
630
631 ph2c = kzalloc(sizeof(*ph2c), GFP_KERNEL);
632 if (!ph2c) {
633 res = _FAIL;
634 goto exit;
635 }
636
637 psetstakey_para = kzalloc(sizeof(*psetstakey_para), GFP_KERNEL);
638 if (!psetstakey_para) {
639 kfree(ph2c);
640 res = _FAIL;
641 goto exit;
642 }
643
644 psetstakey_rsp = kzalloc(sizeof(*psetstakey_rsp), GFP_KERNEL);
645 if (!psetstakey_rsp) {
646 kfree(ph2c);
647 kfree(psetstakey_para);
648 res = _FAIL;
649 goto exit;
650 }
651
652 init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
653 ph2c->rsp = (u8 *)psetstakey_rsp;
654 ph2c->rspsz = sizeof(struct set_stakey_rsp);
655
656 memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
657
658 if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
659 psetstakey_para->algorithm = (unsigned char)psecuritypriv->dot11PrivacyAlgrthm;
660 else
661 GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, false);
662
663 if (unicast_key)
664 memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16);
665 else
666 memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16);
667
668 /* jeff: set this because at least sw key is ready */
669 padapter->securitypriv.busetkipkey = true;
670
671 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
672
673 exit:
674
675 return res;
676 }
677
rtw_clearstakey_cmd(struct adapter * padapter,u8 * psta,u8 entry,u8 enqueue)678 u8 rtw_clearstakey_cmd(struct adapter *padapter, u8 *psta, u8 entry, u8 enqueue)
679 {
680 struct cmd_obj *ph2c;
681 struct set_stakey_parm *psetstakey_para;
682 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
683 struct set_stakey_rsp *psetstakey_rsp = NULL;
684 struct sta_info *sta = (struct sta_info *)psta;
685 u8 res = _SUCCESS;
686
687 if (!enqueue) {
688 clear_cam_entry(padapter, entry);
689 } else {
690 ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
691 if (!ph2c) {
692 res = _FAIL;
693 goto exit;
694 }
695
696 psetstakey_para = kzalloc(sizeof(*psetstakey_para),
697 GFP_ATOMIC);
698 if (!psetstakey_para) {
699 kfree(ph2c);
700 res = _FAIL;
701 goto exit;
702 }
703
704 psetstakey_rsp = kzalloc(sizeof(*psetstakey_rsp),
705 GFP_ATOMIC);
706 if (!psetstakey_rsp) {
707 kfree(ph2c);
708 kfree(psetstakey_para);
709 res = _FAIL;
710 goto exit;
711 }
712
713 init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
714 ph2c->rsp = (u8 *)psetstakey_rsp;
715 ph2c->rspsz = sizeof(struct set_stakey_rsp);
716
717 memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
718
719 psetstakey_para->algorithm = _NO_PRIVACY_;
720
721 psetstakey_para->id = entry;
722
723 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
724 }
725 exit:
726
727 return res;
728 }
729
rtw_addbareq_cmd(struct adapter * padapter,u8 tid,u8 * addr)730 u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr)
731 {
732 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
733 struct cmd_obj *ph2c;
734 struct addBaReq_parm *paddbareq_parm;
735 u8 res = _SUCCESS;
736
737 ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
738 if (!ph2c) {
739 res = _FAIL;
740 goto exit;
741 }
742
743 paddbareq_parm = kzalloc(sizeof(*paddbareq_parm), GFP_ATOMIC);
744 if (!paddbareq_parm) {
745 kfree(ph2c);
746 res = _FAIL;
747 goto exit;
748 }
749
750 paddbareq_parm->tid = tid;
751 memcpy(paddbareq_parm->addr, addr, ETH_ALEN);
752
753 init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq));
754
755 /* rtw_enqueue_cmd(pcmdpriv, ph2c); */
756 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
757
758 exit:
759
760 return res;
761 }
762
rtw_dynamic_chk_wk_cmd(struct adapter * padapter)763 u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter)
764 {
765 struct cmd_obj *ph2c;
766 struct drvextra_cmd_parm *pdrvextra_cmd_parm;
767 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
768 u8 res = _SUCCESS;
769
770 ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
771 if (!ph2c) {
772 res = _FAIL;
773 goto exit;
774 }
775
776 pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
777 if (!pdrvextra_cmd_parm) {
778 kfree(ph2c);
779 res = _FAIL;
780 goto exit;
781 }
782
783 pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID;
784 pdrvextra_cmd_parm->type_size = 0;
785 pdrvextra_cmd_parm->pbuf = (u8 *)padapter;
786
787 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
788
789 /* rtw_enqueue_cmd(pcmdpriv, ph2c); */
790 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
791 exit:
792
793 return res;
794 }
795
rtw_set_chplan_cmd(struct adapter * padapter,u8 chplan)796 u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan)
797 {
798 struct cmd_obj *pcmdobj;
799 struct SetChannelPlan_param *setChannelPlan_param;
800 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
801
802 u8 res = _SUCCESS;
803
804 /* check input parameter */
805 if (!rtw_is_channel_plan_valid(chplan)) {
806 res = _FAIL;
807 goto exit;
808 }
809
810 /* prepare cmd parameter */
811 setChannelPlan_param = kzalloc(sizeof(*setChannelPlan_param),
812 GFP_KERNEL);
813 if (!setChannelPlan_param) {
814 res = _FAIL;
815 goto exit;
816 }
817 setChannelPlan_param->channel_plan = chplan;
818
819 /* need enqueue, prepare cmd_obj and enqueue */
820 pcmdobj = kzalloc(sizeof(*pcmdobj), GFP_KERNEL);
821 if (!pcmdobj) {
822 kfree(setChannelPlan_param);
823 res = _FAIL;
824 goto exit;
825 }
826
827 init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelPlan_param, GEN_CMD_CODE(_SetChannelPlan));
828 res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
829
830 /* do something based on res... */
831 if (res == _SUCCESS)
832 padapter->mlmepriv.ChannelPlan = chplan;
833
834 exit:
835
836 return res;
837 }
838
traffic_status_watchdog(struct adapter * padapter)839 static void traffic_status_watchdog(struct adapter *padapter)
840 {
841 u8 bEnterPS;
842 u8 bBusyTraffic = false, bTxBusyTraffic = false, bRxBusyTraffic = false;
843 u8 bHigherBusyTraffic = false, bHigherBusyRxTraffic = false, bHigherBusyTxTraffic = false;
844 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
845
846 /* */
847 /* Determine if our traffic is busy now */
848 /* */
849 if (check_fwstate(pmlmepriv, _FW_LINKED)) {
850 if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 100 ||
851 pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 100) {
852 bBusyTraffic = true;
853
854 if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
855 bRxBusyTraffic = true;
856 else
857 bTxBusyTraffic = true;
858 }
859
860 /* Higher Tx/Rx data. */
861 if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 ||
862 pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000) {
863 bHigherBusyTraffic = true;
864
865 if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
866 bHigherBusyRxTraffic = true;
867 else
868 bHigherBusyTxTraffic = true;
869 }
870
871 /* check traffic for powersaving. */
872 if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) ||
873 (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2))
874 bEnterPS = false;
875 else
876 bEnterPS = true;
877
878 /* LeisurePS only work in infra mode. */
879 if (bEnterPS)
880 LPS_Enter(padapter);
881 else
882 LPS_Leave(padapter);
883 } else {
884 LPS_Leave(padapter);
885 }
886
887 pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0;
888 pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0;
889 pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0;
890 pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic;
891 pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic;
892 pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic;
893 pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic;
894 pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic;
895 pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic;
896 }
897
rtl8188e_sreset_xmit_status_check(struct adapter * padapter)898 static void rtl8188e_sreset_xmit_status_check(struct adapter *padapter)
899 {
900 u32 txdma_status;
901 int res;
902
903 res = rtw_read32(padapter, REG_TXDMA_STATUS, &txdma_status);
904 if (res)
905 return;
906
907 if (txdma_status != 0x00)
908 rtw_write32(padapter, REG_TXDMA_STATUS, txdma_status);
909 /* total xmit irp = 4 */
910 }
911
dynamic_chk_wk_hdl(struct adapter * padapter,u8 * pbuf)912 static void dynamic_chk_wk_hdl(struct adapter *padapter, u8 *pbuf)
913 {
914 struct mlme_priv *pmlmepriv;
915
916 padapter = (struct adapter *)pbuf;
917 pmlmepriv = &padapter->mlmepriv;
918
919 if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
920 expire_timeout_chk(padapter);
921
922 rtl8188e_sreset_xmit_status_check(padapter);
923
924 linked_status_chk(padapter);
925 traffic_status_watchdog(padapter);
926
927 rtl8188e_HalDmWatchDog(padapter);
928 }
929
lps_ctrl_wk_hdl(struct adapter * padapter,u8 lps_ctrl_type)930 static void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type)
931 {
932 struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
933 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
934 u8 mstatus;
935
936 if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ||
937 check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))
938 return;
939
940 switch (lps_ctrl_type) {
941 case LPS_CTRL_SCAN:
942 if (check_fwstate(pmlmepriv, _FW_LINKED)) {
943 /* connect */
944 LPS_Leave(padapter);
945 }
946 break;
947 case LPS_CTRL_JOINBSS:
948 LPS_Leave(padapter);
949 break;
950 case LPS_CTRL_CONNECT:
951 mstatus = 1;/* connect */
952 /* Reset LPS Setting */
953 padapter->pwrctrlpriv.LpsIdleCount = 0;
954 rtl8188e_set_FwJoinBssReport_cmd(padapter, mstatus);
955 break;
956 case LPS_CTRL_DISCONNECT:
957 mstatus = 0;/* disconnect */
958 LPS_Leave(padapter);
959 rtl8188e_set_FwJoinBssReport_cmd(padapter, mstatus);
960 break;
961 case LPS_CTRL_SPECIAL_PACKET:
962 pwrpriv->DelayLPSLastTimeStamp = jiffies;
963 LPS_Leave(padapter);
964 break;
965 case LPS_CTRL_LEAVE:
966 LPS_Leave(padapter);
967 break;
968 default:
969 break;
970 }
971
972 }
973
rtw_lps_ctrl_wk_cmd(struct adapter * padapter,u8 lps_ctrl_type,u8 enqueue)974 u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue)
975 {
976 struct cmd_obj *ph2c;
977 struct drvextra_cmd_parm *pdrvextra_cmd_parm;
978 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
979 /* struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; */
980 u8 res = _SUCCESS;
981
982 /* if (!pwrctrlpriv->bLeisurePs) */
983 /* return res; */
984
985 if (enqueue) {
986 ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
987 if (!ph2c) {
988 res = _FAIL;
989 goto exit;
990 }
991
992 pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm),
993 GFP_ATOMIC);
994 if (!pdrvextra_cmd_parm) {
995 kfree(ph2c);
996 res = _FAIL;
997 goto exit;
998 }
999
1000 pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID;
1001 pdrvextra_cmd_parm->type_size = lps_ctrl_type;
1002 pdrvextra_cmd_parm->pbuf = NULL;
1003
1004 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1005
1006 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1007 } else {
1008 lps_ctrl_wk_hdl(padapter, lps_ctrl_type);
1009 }
1010
1011 exit:
1012
1013 return res;
1014 }
1015
rpt_timer_setting_wk_hdl(struct adapter * padapter,u16 min_time)1016 static void rpt_timer_setting_wk_hdl(struct adapter *padapter, u16 min_time)
1017 {
1018 struct hal_data_8188e *haldata = &padapter->haldata;
1019 struct odm_dm_struct *odmpriv = &haldata->odmpriv;
1020
1021 ODM_RA_Set_TxRPT_Time(odmpriv, min_time);
1022 }
1023
rtw_rpt_timer_cfg_cmd(struct adapter * padapter,u16 min_time)1024 u8 rtw_rpt_timer_cfg_cmd(struct adapter *padapter, u16 min_time)
1025 {
1026 struct cmd_obj *ph2c;
1027 struct drvextra_cmd_parm *pdrvextra_cmd_parm;
1028 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1029
1030 u8 res = _SUCCESS;
1031
1032 ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
1033 if (!ph2c) {
1034 res = _FAIL;
1035 goto exit;
1036 }
1037
1038 pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm),
1039 GFP_ATOMIC);
1040 if (!pdrvextra_cmd_parm) {
1041 kfree(ph2c);
1042 res = _FAIL;
1043 goto exit;
1044 }
1045
1046 pdrvextra_cmd_parm->ec_id = RTP_TIMER_CFG_WK_CID;
1047 pdrvextra_cmd_parm->type_size = min_time;
1048 pdrvextra_cmd_parm->pbuf = NULL;
1049 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1050 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1051 exit:
1052
1053 return res;
1054 }
1055
antenna_select_wk_hdl(struct adapter * padapter,u8 antenna)1056 static void antenna_select_wk_hdl(struct adapter *padapter, u8 antenna)
1057 {
1058 struct hal_data_8188e *haldata = &padapter->haldata;
1059
1060 /* switch current antenna to optimum antenna */
1061 if (haldata->CurAntenna != antenna) {
1062 ODM_UpdateRxIdleAnt_88E(&haldata->odmpriv, antenna == 2 ? MAIN_ANT : AUX_ANT);
1063 haldata->CurAntenna = antenna;
1064 }
1065 }
1066
rtw_antenna_diversity(struct adapter * adapter)1067 static bool rtw_antenna_diversity(struct adapter *adapter)
1068 {
1069 struct hal_data_8188e *haldata = &adapter->haldata;
1070
1071 return haldata->AntDivCfg != 0;
1072 }
1073
rtw_antenna_select_cmd(struct adapter * padapter,u8 antenna,u8 enqueue)1074 u8 rtw_antenna_select_cmd(struct adapter *padapter, u8 antenna, u8 enqueue)
1075 {
1076 struct cmd_obj *ph2c;
1077 struct drvextra_cmd_parm *pdrvextra_cmd_parm;
1078 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1079 u8 res = _SUCCESS;
1080
1081 if (!rtw_antenna_diversity(padapter))
1082 return res;
1083
1084 if (enqueue) {
1085 ph2c = kzalloc(sizeof(*ph2c), GFP_KERNEL);
1086 if (!ph2c) {
1087 res = _FAIL;
1088 goto exit;
1089 }
1090
1091 pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm),
1092 GFP_KERNEL);
1093 if (!pdrvextra_cmd_parm) {
1094 kfree(ph2c);
1095 res = _FAIL;
1096 goto exit;
1097 }
1098
1099 pdrvextra_cmd_parm->ec_id = ANT_SELECT_WK_CID;
1100 pdrvextra_cmd_parm->type_size = antenna;
1101 pdrvextra_cmd_parm->pbuf = NULL;
1102 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1103
1104 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1105 } else {
1106 antenna_select_wk_hdl(padapter, antenna);
1107 }
1108 exit:
1109
1110 return res;
1111 }
1112
p2p_protocol_wk_cmd(struct adapter * padapter,int intCmdType)1113 u8 p2p_protocol_wk_cmd(struct adapter *padapter, int intCmdType)
1114 {
1115 struct cmd_obj *ph2c;
1116 struct drvextra_cmd_parm *pdrvextra_cmd_parm;
1117 struct wifidirect_info *pwdinfo = &padapter->wdinfo;
1118 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1119 u8 res = _SUCCESS;
1120
1121 if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
1122 return res;
1123
1124 ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
1125 if (!ph2c) {
1126 res = _FAIL;
1127 goto exit;
1128 }
1129
1130 pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
1131 if (!pdrvextra_cmd_parm) {
1132 kfree(ph2c);
1133 res = _FAIL;
1134 goto exit;
1135 }
1136
1137 pdrvextra_cmd_parm->ec_id = P2P_PROTO_WK_CID;
1138 pdrvextra_cmd_parm->type_size = intCmdType; /* As the command type. */
1139 pdrvextra_cmd_parm->pbuf = NULL; /* Must be NULL here */
1140
1141 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1142
1143 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1144
1145 exit:
1146
1147 return res;
1148 }
1149
rtw_ps_cmd(struct adapter * padapter)1150 u8 rtw_ps_cmd(struct adapter *padapter)
1151 {
1152 struct cmd_obj *ppscmd;
1153 struct drvextra_cmd_parm *pdrvextra_cmd_parm;
1154 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1155
1156 u8 res = _SUCCESS;
1157
1158 ppscmd = kzalloc(sizeof(*ppscmd), GFP_ATOMIC);
1159 if (!ppscmd) {
1160 res = _FAIL;
1161 goto exit;
1162 }
1163
1164 pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
1165 if (!pdrvextra_cmd_parm) {
1166 kfree(ppscmd);
1167 res = _FAIL;
1168 goto exit;
1169 }
1170
1171 pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID;
1172 pdrvextra_cmd_parm->pbuf = NULL;
1173 init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1174
1175 res = rtw_enqueue_cmd(pcmdpriv, ppscmd);
1176
1177 exit:
1178
1179 return res;
1180 }
1181
rtw_is_hi_queue_empty(struct adapter * adapter)1182 static bool rtw_is_hi_queue_empty(struct adapter *adapter)
1183 {
1184 int res;
1185 u32 reg;
1186
1187 res = rtw_read32(adapter, REG_HGQ_INFORMATION, ®);
1188 if (res)
1189 return false;
1190
1191 return (reg & 0x0000ff00) == 0;
1192 }
1193
rtw_chk_hi_queue_hdl(struct adapter * padapter)1194 static void rtw_chk_hi_queue_hdl(struct adapter *padapter)
1195 {
1196 int cnt = 0;
1197 struct sta_info *psta_bmc;
1198 struct sta_priv *pstapriv = &padapter->stapriv;
1199
1200 psta_bmc = rtw_get_bcmc_stainfo(padapter);
1201 if (!psta_bmc)
1202 return;
1203
1204 if (psta_bmc->sleepq_len == 0) {
1205 bool val = rtw_is_hi_queue_empty(padapter);
1206
1207 while (!val) {
1208 msleep(100);
1209
1210 cnt++;
1211
1212 if (cnt > 10)
1213 break;
1214
1215 val = rtw_is_hi_queue_empty(padapter);
1216 }
1217
1218 if (cnt <= 10) {
1219 pstapriv->tim_bitmap &= ~BIT(0);
1220 pstapriv->sta_dz_bitmap &= ~BIT(0);
1221
1222 update_beacon(padapter, _TIM_IE_, NULL, false);
1223 } else { /* re check again */
1224 rtw_chk_hi_queue_cmd(padapter);
1225 }
1226 }
1227 }
1228
rtw_chk_hi_queue_cmd(struct adapter * padapter)1229 u8 rtw_chk_hi_queue_cmd(struct adapter *padapter)
1230 {
1231 struct cmd_obj *ph2c;
1232 struct drvextra_cmd_parm *pdrvextra_cmd_parm;
1233 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1234 u8 res = _SUCCESS;
1235
1236 ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
1237 if (!ph2c) {
1238 res = _FAIL;
1239 goto exit;
1240 }
1241
1242 pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
1243 if (!pdrvextra_cmd_parm) {
1244 kfree(ph2c);
1245 res = _FAIL;
1246 goto exit;
1247 }
1248
1249 pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID;
1250 pdrvextra_cmd_parm->type_size = 0;
1251 pdrvextra_cmd_parm->pbuf = NULL;
1252
1253 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1254
1255 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1256 exit:
1257 return res;
1258 }
1259
rtw_c2h_wk_cmd(struct adapter * padapter,u8 * c2h_evt)1260 u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt)
1261 {
1262 struct cmd_obj *ph2c;
1263 struct drvextra_cmd_parm *pdrvextra_cmd_parm;
1264 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1265 u8 res = _SUCCESS;
1266
1267 ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
1268 if (!ph2c) {
1269 res = _FAIL;
1270 goto exit;
1271 }
1272
1273 pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
1274 if (!pdrvextra_cmd_parm) {
1275 kfree(ph2c);
1276 res = _FAIL;
1277 goto exit;
1278 }
1279
1280 pdrvextra_cmd_parm->ec_id = C2H_WK_CID;
1281 pdrvextra_cmd_parm->type_size = c2h_evt ? 16 : 0;
1282 pdrvextra_cmd_parm->pbuf = c2h_evt;
1283
1284 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1285
1286 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1287
1288 exit:
1289
1290 return res;
1291 }
1292
c2h_evt_hdl(struct adapter * adapter,struct c2h_evt_hdr * c2h_evt,c2h_id_filter filter)1293 static void c2h_evt_hdl(struct adapter *adapter, struct c2h_evt_hdr *c2h_evt, c2h_id_filter filter)
1294 {
1295 u8 buf[16];
1296
1297 if (!c2h_evt)
1298 c2h_evt_read(adapter, buf);
1299 }
1300
c2h_wk_callback(struct work_struct * work)1301 static void c2h_wk_callback(struct work_struct *work)
1302 {
1303 struct evt_priv *evtpriv = container_of(work, struct evt_priv, c2h_wk);
1304 struct adapter *adapter = container_of(evtpriv, struct adapter, evtpriv);
1305 struct c2h_evt_hdr *c2h_evt;
1306
1307 evtpriv->c2h_wk_alive = true;
1308
1309 while (!rtw_cbuf_empty(evtpriv->c2h_queue)) {
1310 c2h_evt = (struct c2h_evt_hdr *)rtw_cbuf_pop(evtpriv->c2h_queue);
1311 if (c2h_evt) {
1312 /* This C2H event is read, clear it */
1313 rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE);
1314 } else {
1315 c2h_evt = kmalloc(16, GFP_KERNEL);
1316 if (c2h_evt) {
1317 /* This C2H event is not read, read & clear now */
1318 if (c2h_evt_read(adapter, (u8 *)c2h_evt) != _SUCCESS) {
1319 kfree(c2h_evt);
1320 continue;
1321 }
1322 } else {
1323 return;
1324 }
1325 }
1326
1327 /* Special pointer to trigger c2h_evt_clear only */
1328 if ((void *)c2h_evt == (void *)evtpriv)
1329 continue;
1330
1331 if (!c2h_evt_exist(c2h_evt)) {
1332 kfree(c2h_evt);
1333 continue;
1334 }
1335
1336 /* Enqueue into cmd_thread for others */
1337 rtw_c2h_wk_cmd(adapter, (u8 *)c2h_evt);
1338 }
1339
1340 evtpriv->c2h_wk_alive = false;
1341 }
1342
rtw_drvextra_cmd_hdl(struct adapter * padapter,unsigned char * pbuf)1343 u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf)
1344 {
1345 struct drvextra_cmd_parm *pdrvextra_cmd;
1346
1347 if (!pbuf)
1348 return H2C_PARAMETERS_ERROR;
1349
1350 pdrvextra_cmd = (struct drvextra_cmd_parm *)pbuf;
1351
1352 switch (pdrvextra_cmd->ec_id) {
1353 case DYNAMIC_CHK_WK_CID:
1354 dynamic_chk_wk_hdl(padapter, pdrvextra_cmd->pbuf);
1355 break;
1356 case POWER_SAVING_CTRL_WK_CID:
1357 rtw_ps_processor(padapter);
1358 break;
1359 case LPS_CTRL_WK_CID:
1360 lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type_size);
1361 break;
1362 case RTP_TIMER_CFG_WK_CID:
1363 rpt_timer_setting_wk_hdl(padapter, pdrvextra_cmd->type_size);
1364 break;
1365 case ANT_SELECT_WK_CID:
1366 antenna_select_wk_hdl(padapter, pdrvextra_cmd->type_size);
1367 break;
1368 case P2P_PS_WK_CID:
1369 p2p_ps_wk_hdl(padapter, pdrvextra_cmd->type_size);
1370 break;
1371 case P2P_PROTO_WK_CID:
1372 /* Commented by Albert 2011/07/01 */
1373 /* I used the type_size as the type command */
1374 p2p_protocol_wk_hdl(padapter, pdrvextra_cmd->type_size);
1375 break;
1376 case CHECK_HIQ_WK_CID:
1377 rtw_chk_hi_queue_hdl(padapter);
1378 break;
1379 case C2H_WK_CID:
1380 c2h_evt_hdl(padapter, (struct c2h_evt_hdr *)pdrvextra_cmd->pbuf, NULL);
1381 break;
1382 default:
1383 break;
1384 }
1385
1386 if (pdrvextra_cmd->pbuf && pdrvextra_cmd->type_size > 0)
1387 kfree(pdrvextra_cmd->pbuf);
1388
1389 return H2C_SUCCESS;
1390 }
1391
rtw_survey_cmd_callback(struct adapter * padapter,struct cmd_obj * pcmd)1392 void rtw_survey_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
1393 {
1394 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1395
1396 if (pcmd->res != H2C_SUCCESS) {
1397 /* TODO: cancel timer and do timeout handler directly... */
1398 _set_timer(&pmlmepriv->scan_to_timer, 1);
1399 }
1400
1401 /* free cmd */
1402 rtw_free_cmd_obj(pcmd);
1403
1404 }
1405
rtw_disassoc_cmd_callback(struct adapter * padapter,struct cmd_obj * pcmd)1406 void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
1407 {
1408 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1409
1410 if (pcmd->res != H2C_SUCCESS) {
1411 spin_lock_bh(&pmlmepriv->lock);
1412 set_fwstate(pmlmepriv, _FW_LINKED);
1413 spin_unlock_bh(&pmlmepriv->lock);
1414
1415 return;
1416 }
1417
1418 /* clear bridge database */
1419 nat25_db_cleanup(padapter);
1420
1421 /* free cmd */
1422 rtw_free_cmd_obj(pcmd);
1423 }
1424
rtw_joinbss_cmd_callback(struct adapter * padapter,struct cmd_obj * pcmd)1425 void rtw_joinbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
1426 {
1427 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1428
1429 if (pcmd->res != H2C_SUCCESS) {
1430 /* TODO: cancel timer and do timeout handler directly... */
1431 _set_timer(&pmlmepriv->assoc_timer, 1);
1432 }
1433
1434 rtw_free_cmd_obj(pcmd);
1435 }
1436
rtw_createbss_cmd_callback(struct adapter * padapter,struct cmd_obj * pcmd)1437 void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
1438 {
1439 struct sta_info *psta = NULL;
1440 struct wlan_network *pwlan = NULL;
1441 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1442 struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf;
1443 struct wlan_network *tgt_network = &pmlmepriv->cur_network;
1444
1445 if (pcmd->res != H2C_SUCCESS)
1446 _set_timer(&pmlmepriv->assoc_timer, 1);
1447
1448 del_timer_sync(&pmlmepriv->assoc_timer);
1449
1450 spin_lock_bh(&pmlmepriv->lock);
1451
1452 if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
1453 psta = rtw_get_stainfo(&padapter->stapriv, pnetwork->MacAddress);
1454 if (!psta) {
1455 psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress);
1456 if (!psta)
1457 goto createbss_cmd_fail;
1458 }
1459
1460 rtw_indicate_connect(padapter);
1461 } else {
1462
1463 pwlan = rtw_alloc_network(pmlmepriv);
1464 spin_lock_bh(&pmlmepriv->scanned_queue.lock);
1465 if (!pwlan) {
1466 pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue);
1467 if (!pwlan) {
1468 spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
1469 goto createbss_cmd_fail;
1470 }
1471 pwlan->last_scanned = jiffies;
1472 } else {
1473 list_add_tail(&pwlan->list, &pmlmepriv->scanned_queue.queue);
1474 }
1475
1476 pnetwork->Length = get_wlan_bssid_ex_sz(pnetwork);
1477 memcpy(&pwlan->network, pnetwork, pnetwork->Length);
1478
1479 memcpy(&tgt_network->network, pnetwork, (get_wlan_bssid_ex_sz(pnetwork)));
1480
1481 _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
1482
1483 spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
1484 /* we will set _FW_LINKED when there is one more sat to join us (rtw_stassoc_event_callback) */
1485 }
1486
1487 createbss_cmd_fail:
1488
1489 spin_unlock_bh(&pmlmepriv->lock);
1490
1491 rtw_free_cmd_obj(pcmd);
1492
1493 }
1494
rtw_setstaKey_cmdrsp_callback(struct adapter * padapter,struct cmd_obj * pcmd)1495 void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
1496 {
1497 struct sta_priv *pstapriv = &padapter->stapriv;
1498 struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *)(pcmd->rsp);
1499 struct sta_info *psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr);
1500
1501 if (!psta)
1502 goto exit;
1503 exit:
1504 rtw_free_cmd_obj(pcmd);
1505
1506 }
1507
rtw_setassocsta_cmdrsp_callback(struct adapter * padapter,struct cmd_obj * pcmd)1508 void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
1509 {
1510 struct sta_priv *pstapriv = &padapter->stapriv;
1511 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1512 struct set_assocsta_parm *passocsta_parm = (struct set_assocsta_parm *)(pcmd->parmbuf);
1513 struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *)(pcmd->rsp);
1514 struct sta_info *psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr);
1515
1516 if (!psta)
1517 goto exit;
1518
1519 psta->aid = passocsta_rsp->cam_id;
1520 psta->mac_id = passocsta_rsp->cam_id;
1521
1522 spin_lock_bh(&pmlmepriv->lock);
1523
1524 if (check_fwstate(pmlmepriv, WIFI_MP_STATE) && check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
1525 _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
1526
1527 set_fwstate(pmlmepriv, _FW_LINKED);
1528 spin_unlock_bh(&pmlmepriv->lock);
1529
1530 exit:
1531 rtw_free_cmd_obj(pcmd);
1532
1533 }
1534