1// SPDX-License-Identifier: GPL-2.0
2/******************************************************************************
3 * rtl871x_cmd.c
4 *
5 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
6 * Linux device driver for RTL8192SU
7 *
8 * Modifications for inclusion into the Linux staging tree are
9 * Copyright(c) 2010 Larry Finger. All rights reserved.
10 *
11 * Contact information:
12 * WLAN FAE <wlanfae@realtek.com>
13 * Larry Finger <Larry.Finger@lwfinger.net>
14 *
15 ******************************************************************************/
16
17#define _RTL871X_CMD_C_
18
19#include <linux/compiler.h>
20#include <linux/kernel.h>
21#include <linux/errno.h>
22#include <linux/slab.h>
23#include <linux/module.h>
24#include <linux/kref.h>
25#include <linux/netdevice.h>
26#include <linux/skbuff.h>
27#include <linux/usb.h>
28#include <linux/usb/ch9.h>
29#include <linux/circ_buf.h>
30#include <linux/uaccess.h>
31#include <asm/byteorder.h>
32#include <linux/atomic.h>
33#include <linux/semaphore.h>
34#include <linux/rtnetlink.h>
35
36#include "osdep_service.h"
37#include "drv_types.h"
38#include "recv_osdep.h"
39#include "mlme_osdep.h"
40
41/*
42 * Caller and the r8712_cmd_thread can protect cmd_q by spin_lock.
43 * No irqsave is necessary.
44 */
45
46int r8712_init_cmd_priv(struct cmd_priv *pcmdpriv)
47{
48	init_completion(&pcmdpriv->cmd_queue_comp);
49	init_completion(&pcmdpriv->terminate_cmdthread_comp);
50
51	_init_queue(&(pcmdpriv->cmd_queue));
52
53	/* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
54	pcmdpriv->cmd_seq = 1;
55	pcmdpriv->cmd_allocated_buf = kmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ,
56					      GFP_ATOMIC);
57	if (!pcmdpriv->cmd_allocated_buf)
58		return -ENOMEM;
59	pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf  +  CMDBUFF_ALIGN_SZ -
60			    ((addr_t)(pcmdpriv->cmd_allocated_buf) &
61			    (CMDBUFF_ALIGN_SZ - 1));
62	pcmdpriv->rsp_allocated_buf = kmalloc(MAX_RSPSZ + 4, GFP_ATOMIC);
63	if (!pcmdpriv->rsp_allocated_buf) {
64		kfree(pcmdpriv->cmd_allocated_buf);
65		pcmdpriv->cmd_allocated_buf = NULL;
66		return -ENOMEM;
67	}
68	pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf  +  4 -
69			    ((addr_t)(pcmdpriv->rsp_allocated_buf) & 3);
70	pcmdpriv->cmd_issued_cnt = 0;
71	pcmdpriv->cmd_done_cnt = 0;
72	pcmdpriv->rsp_cnt = 0;
73	return 0;
74}
75
76int r8712_init_evt_priv(struct evt_priv *pevtpriv)
77{
78	/* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
79	pevtpriv->event_seq = 0;
80	pevtpriv->evt_allocated_buf = kmalloc(MAX_EVTSZ + 4, GFP_ATOMIC);
81
82	if (!pevtpriv->evt_allocated_buf)
83		return -ENOMEM;
84	pevtpriv->evt_buf = pevtpriv->evt_allocated_buf  +  4 -
85			    ((addr_t)(pevtpriv->evt_allocated_buf) & 3);
86	pevtpriv->evt_done_cnt = 0;
87	return 0;
88}
89
90void r8712_free_evt_priv(struct evt_priv *pevtpriv)
91{
92	kfree(pevtpriv->evt_allocated_buf);
93}
94
95void r8712_free_cmd_priv(struct cmd_priv *pcmdpriv)
96{
97	if (pcmdpriv) {
98		kfree(pcmdpriv->cmd_allocated_buf);
99		kfree(pcmdpriv->rsp_allocated_buf);
100	}
101}
102
103/*
104 * Calling Context:
105 *
106 * r8712_enqueue_cmd can only be called between kernel thread,
107 * since only spin_lock is used.
108 *
109 * ISR/Call-Back functions can't call this sub-function.
110 *
111 */
112
113void r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj)
114{
115	struct __queue *queue;
116	unsigned long irqL;
117
118	if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag)
119		return;
120	if (!obj)
121		return;
122	queue = &pcmdpriv->cmd_queue;
123	spin_lock_irqsave(&queue->lock, irqL);
124	list_add_tail(&obj->list, &queue->queue);
125	spin_unlock_irqrestore(&queue->lock, irqL);
126	complete(&pcmdpriv->cmd_queue_comp);
127}
128
129struct cmd_obj *r8712_dequeue_cmd(struct  __queue *queue)
130{
131	unsigned long irqL;
132	struct cmd_obj *obj;
133
134	spin_lock_irqsave(&queue->lock, irqL);
135	obj = list_first_entry_or_null(&queue->queue,
136				       struct cmd_obj, list);
137	if (obj)
138		list_del_init(&obj->list);
139	spin_unlock_irqrestore(&queue->lock, irqL);
140	return obj;
141}
142
143void r8712_enqueue_cmd_ex(struct cmd_priv *pcmdpriv, struct cmd_obj *obj)
144{
145	unsigned long irqL;
146	struct  __queue *queue;
147
148	if (!obj)
149		return;
150	if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag)
151		return;
152	queue = &pcmdpriv->cmd_queue;
153	spin_lock_irqsave(&queue->lock, irqL);
154	list_add_tail(&obj->list, &queue->queue);
155	spin_unlock_irqrestore(&queue->lock, irqL);
156	complete(&pcmdpriv->cmd_queue_comp);
157}
158
159void r8712_free_cmd_obj(struct cmd_obj *pcmd)
160{
161	if ((pcmd->cmdcode != _JoinBss_CMD_) &&
162	    (pcmd->cmdcode != _CreateBss_CMD_))
163		kfree(pcmd->parmbuf);
164	if (pcmd->rsp) {
165		if (pcmd->rspsz != 0)
166			kfree(pcmd->rsp);
167	}
168	kfree(pcmd);
169}
170
171u8 r8712_sitesurvey_cmd(struct _adapter *padapter,
172			struct ndis_802_11_ssid *pssid)
173	__must_hold(&padapter->mlmepriv.lock)
174{
175	struct cmd_obj	*ph2c;
176	struct sitesurvey_parm	*psurveyPara;
177	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
178	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
179
180	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
181	if (!ph2c)
182		return _FAIL;
183	psurveyPara = kmalloc(sizeof(*psurveyPara), GFP_ATOMIC);
184	if (!psurveyPara) {
185		kfree(ph2c);
186		return _FAIL;
187	}
188	init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara,
189				   GEN_CMD_CODE(_SiteSurvey));
190	psurveyPara->bsslimit = cpu_to_le32(48);
191	psurveyPara->passive_mode = cpu_to_le32(pmlmepriv->passive_mode);
192	psurveyPara->ss_ssidlen = 0;
193	memset(psurveyPara->ss_ssid, 0, IW_ESSID_MAX_SIZE + 1);
194	if (pssid && pssid->SsidLength) {
195		int len = min_t(int, pssid->SsidLength, IW_ESSID_MAX_SIZE);
196
197		memcpy(psurveyPara->ss_ssid, pssid->Ssid, len);
198		psurveyPara->ss_ssidlen = cpu_to_le32(len);
199	}
200	set_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
201	r8712_enqueue_cmd(pcmdpriv, ph2c);
202	mod_timer(&pmlmepriv->scan_to_timer,
203		  jiffies + msecs_to_jiffies(SCANNING_TIMEOUT));
204	padapter->ledpriv.LedControlHandler(padapter, LED_CTL_SITE_SURVEY);
205	complete(&padapter->rx_filter_ready);
206	return _SUCCESS;
207}
208
209int r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset)
210{
211	struct cmd_obj		*ph2c;
212	struct setdatarate_parm	*pbsetdataratepara;
213	struct cmd_priv		*pcmdpriv = &padapter->cmdpriv;
214
215	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
216	if (!ph2c)
217		return -ENOMEM;
218	pbsetdataratepara = kmalloc(sizeof(*pbsetdataratepara), GFP_ATOMIC);
219	if (!pbsetdataratepara) {
220		kfree(ph2c);
221		return -ENOMEM;
222	}
223	init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara,
224				   GEN_CMD_CODE(_SetDataRate));
225	pbsetdataratepara->mac_id = 5;
226	memcpy(pbsetdataratepara->datarates, rateset, NumRates);
227	r8712_enqueue_cmd(pcmdpriv, ph2c);
228	return 0;
229}
230
231void r8712_set_chplan_cmd(struct _adapter *padapter, int chplan)
232{
233	struct cmd_obj *ph2c;
234	struct SetChannelPlan_param *psetchplanpara;
235	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
236
237	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
238	if (!ph2c)
239		return;
240	psetchplanpara = kmalloc(sizeof(*psetchplanpara), GFP_ATOMIC);
241	if (!psetchplanpara) {
242		kfree(ph2c);
243		return;
244	}
245	init_h2fwcmd_w_parm_no_rsp(ph2c, psetchplanpara, GEN_CMD_CODE(_SetChannelPlan));
246	psetchplanpara->ChannelPlan = chplan;
247	r8712_enqueue_cmd(pcmdpriv, ph2c);
248}
249
250int r8712_setrfreg_cmd(struct _adapter  *padapter, u8 offset, u32 val)
251{
252	struct cmd_obj *ph2c;
253	struct writeRF_parm *pwriterfparm;
254	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
255
256	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
257	if (!ph2c)
258		return -ENOMEM;
259	pwriterfparm = kmalloc(sizeof(*pwriterfparm), GFP_ATOMIC);
260	if (!pwriterfparm) {
261		kfree(ph2c);
262		return -ENOMEM;
263	}
264	init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg));
265	pwriterfparm->offset = offset;
266	pwriterfparm->value = val;
267	r8712_enqueue_cmd(pcmdpriv, ph2c);
268	return 0;
269}
270
271int r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval)
272{
273	struct cmd_obj *ph2c;
274	struct readRF_parm *prdrfparm;
275	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
276
277	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
278	if (!ph2c)
279		return -ENOMEM;
280	prdrfparm = kmalloc(sizeof(*prdrfparm), GFP_ATOMIC);
281	if (!prdrfparm) {
282		kfree(ph2c);
283		return -ENOMEM;
284	}
285	INIT_LIST_HEAD(&ph2c->list);
286	ph2c->cmdcode = GEN_CMD_CODE(_GetRFReg);
287	ph2c->parmbuf = (unsigned char *)prdrfparm;
288	ph2c->cmdsz =  sizeof(struct readRF_parm);
289	ph2c->rsp = pval;
290	ph2c->rspsz = sizeof(struct readRF_rsp);
291	prdrfparm->offset = offset;
292	r8712_enqueue_cmd(pcmdpriv, ph2c);
293	return 0;
294}
295
296void r8712_getbbrfreg_cmdrsp_callback(struct _adapter *padapter,
297				      struct cmd_obj *pcmd)
298{
299	kfree(pcmd->parmbuf);
300	kfree(pcmd);
301	padapter->mppriv.workparam.bcompleted = true;
302}
303
304void r8712_readtssi_cmdrsp_callback(struct _adapter *padapter, struct cmd_obj *pcmd)
305{
306	kfree(pcmd->parmbuf);
307	kfree(pcmd);
308
309	padapter->mppriv.workparam.bcompleted = true;
310}
311
312int r8712_createbss_cmd(struct _adapter *padapter)
313{
314	struct cmd_obj *pcmd;
315	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
316	struct wlan_bssid_ex *pdev_network =
317				 &padapter->registrypriv.dev_network;
318
319	padapter->ledpriv.LedControlHandler(padapter, LED_CTL_START_TO_LINK);
320	pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC);
321	if (!pcmd)
322		return -ENOMEM;
323	INIT_LIST_HEAD(&pcmd->list);
324	pcmd->cmdcode = _CreateBss_CMD_;
325	pcmd->parmbuf = (unsigned char *)pdev_network;
326	pcmd->cmdsz = r8712_get_wlan_bssid_ex_sz(pdev_network);
327	pcmd->rsp = NULL;
328	pcmd->rspsz = 0;
329	/* notes: translate IELength & Length after assign to cmdsz; */
330	pdev_network->Length = pcmd->cmdsz;
331	pdev_network->IELength = pdev_network->IELength;
332	pdev_network->Ssid.SsidLength =	pdev_network->Ssid.SsidLength;
333	r8712_enqueue_cmd(pcmdpriv, pcmd);
334	return 0;
335}
336
337int r8712_joinbss_cmd(struct _adapter  *padapter, struct wlan_network *pnetwork)
338{
339	struct wlan_bssid_ex *psecnetwork;
340	struct cmd_obj		*pcmd;
341	struct cmd_priv		*pcmdpriv = &padapter->cmdpriv;
342	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
343	struct qos_priv		*pqospriv = &pmlmepriv->qospriv;
344	struct security_priv	*psecuritypriv = &padapter->securitypriv;
345	struct registry_priv	*pregistrypriv = &padapter->registrypriv;
346	enum NDIS_802_11_NETWORK_INFRASTRUCTURE ndis_network_mode =
347		pnetwork->network.InfrastructureMode;
348
349	padapter->ledpriv.LedControlHandler(padapter, LED_CTL_START_TO_LINK);
350	pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC);
351	if (!pcmd)
352		return -ENOMEM;
353
354	/* for hidden ap to set fw_state here */
355	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) !=
356	    true) {
357		switch (ndis_network_mode) {
358		case Ndis802_11IBSS:
359			pmlmepriv->fw_state |= WIFI_ADHOC_STATE;
360			break;
361		case Ndis802_11Infrastructure:
362			pmlmepriv->fw_state |= WIFI_STATION_STATE;
363			break;
364		case Ndis802_11APMode:
365		case Ndis802_11AutoUnknown:
366		case Ndis802_11InfrastructureMax:
367			break;
368		}
369	}
370	psecnetwork = &psecuritypriv->sec_bss;
371	memcpy(psecnetwork, &pnetwork->network, sizeof(*psecnetwork));
372	psecuritypriv->authenticator_ie[0] = (unsigned char)
373					     psecnetwork->IELength;
374	if ((psecnetwork->IELength - 12) < (256 - 1))
375		memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12],
376		       psecnetwork->IELength - 12);
377	else
378		memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], (256 - 1));
379	psecnetwork->IELength = 0;
380	/*
381	 * If the driver wants to use the bssid to create the connection.
382	 * If not, we copy the connecting AP's MAC address to it so that
383	 * the driver just has the bssid information for PMKIDList searching.
384	 */
385	if (!pmlmepriv->assoc_by_bssid)
386		ether_addr_copy(&pmlmepriv->assoc_bssid[0],
387				&pnetwork->network.MacAddress[0]);
388	psecnetwork->IELength = r8712_restruct_sec_ie(padapter, &pnetwork->network.IEs[0],
389						      &psecnetwork->IEs[0], pnetwork->network.IELength);
390	pqospriv->qos_option = 0;
391	if (pregistrypriv->wmm_enable) {
392		u32 tmp_len;
393
394		tmp_len = r8712_restruct_wmm_ie(padapter, &pnetwork->network.IEs[0],
395						&psecnetwork->IEs[0], pnetwork->network.IELength,
396						psecnetwork->IELength);
397		if (psecnetwork->IELength != tmp_len) {
398			psecnetwork->IELength = tmp_len;
399			pqospriv->qos_option = 1; /* WMM IE in beacon */
400		} else {
401			pqospriv->qos_option = 0; /* no WMM IE in beacon */
402		}
403	}
404	if (pregistrypriv->ht_enable) {
405		/*
406		 * For WEP mode, we will use the bg mode to do the connection
407		 * to avoid some IOT issues, especially for Realtek 8192u
408		 * SoftAP.
409		 */
410		if ((padapter->securitypriv.PrivacyAlgrthm != _WEP40_) &&
411		    (padapter->securitypriv.PrivacyAlgrthm != _WEP104_)) {
412			/* restructure_ht_ie */
413			r8712_restructure_ht_ie(padapter,
414						&pnetwork->network.IEs[0],
415						&psecnetwork->IEs[0],
416						pnetwork->network.IELength,
417						&psecnetwork->IELength);
418		}
419	}
420	psecuritypriv->supplicant_ie[0] = (u8)psecnetwork->IELength;
421	if (psecnetwork->IELength < 255)
422		memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0],
423		       psecnetwork->IELength);
424	else
425		memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0],
426		       255);
427	/* get cmdsz before endian conversion */
428	pcmd->cmdsz = r8712_get_wlan_bssid_ex_sz(psecnetwork);
429#ifdef __BIG_ENDIAN
430	/* wlan_network endian conversion */
431	psecnetwork->Length = cpu_to_le32(psecnetwork->Length);
432	psecnetwork->Ssid.SsidLength = cpu_to_le32(psecnetwork->Ssid.SsidLength);
433	psecnetwork->Privacy = cpu_to_le32(psecnetwork->Privacy);
434	psecnetwork->Rssi = cpu_to_le32(psecnetwork->Rssi);
435	psecnetwork->NetworkTypeInUse = cpu_to_le32(psecnetwork->NetworkTypeInUse);
436	psecnetwork->Configuration.ATIMWindow = cpu_to_le32(psecnetwork->Configuration.ATIMWindow);
437	psecnetwork->Configuration.BeaconPeriod = cpu_to_le32(psecnetwork->Configuration.BeaconPeriod);
438	psecnetwork->Configuration.DSConfig = cpu_to_le32(psecnetwork->Configuration.DSConfig);
439	psecnetwork->Configuration.FHConfig.DwellTime = cpu_to_le32(psecnetwork->Configuration.FHConfig.DwellTime);
440	psecnetwork->Configuration.FHConfig.HopPattern = cpu_to_le32(psecnetwork->Configuration.FHConfig.HopPattern);
441	psecnetwork->Configuration.FHConfig.HopSet = cpu_to_le32(psecnetwork->Configuration.FHConfig.HopSet);
442	psecnetwork->Configuration.FHConfig.Length = cpu_to_le32(psecnetwork->Configuration.FHConfig.Length);
443	psecnetwork->Configuration.Length = cpu_to_le32(psecnetwork->Configuration.Length);
444	psecnetwork->InfrastructureMode = cpu_to_le32(psecnetwork->InfrastructureMode);
445	psecnetwork->IELength = cpu_to_le32(psecnetwork->IELength);
446#endif
447	INIT_LIST_HEAD(&pcmd->list);
448	pcmd->cmdcode = _JoinBss_CMD_;
449	pcmd->parmbuf = (unsigned char *)psecnetwork;
450	pcmd->rsp = NULL;
451	pcmd->rspsz = 0;
452	r8712_enqueue_cmd(pcmdpriv, pcmd);
453	return 0;
454}
455
456void r8712_disassoc_cmd(struct _adapter *padapter) /* for sta_mode */
457{
458	struct cmd_obj *pdisconnect_cmd;
459	struct disconnect_parm *pdisconnect;
460	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
461
462	pdisconnect_cmd = kmalloc(sizeof(*pdisconnect_cmd), GFP_ATOMIC);
463	if (!pdisconnect_cmd)
464		return;
465	pdisconnect = kmalloc(sizeof(*pdisconnect), GFP_ATOMIC);
466	if (!pdisconnect) {
467		kfree(pdisconnect_cmd);
468		return;
469	}
470	init_h2fwcmd_w_parm_no_rsp(pdisconnect_cmd, pdisconnect, _DisConnect_CMD_);
471	r8712_enqueue_cmd(pcmdpriv, pdisconnect_cmd);
472}
473
474void r8712_setopmode_cmd(struct _adapter *padapter,
475			 enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype)
476{
477	struct cmd_obj *ph2c;
478	struct setopmode_parm *psetop;
479
480	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
481
482	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
483	if (!ph2c)
484		return;
485	psetop = kmalloc(sizeof(*psetop), GFP_ATOMIC);
486	if (!psetop) {
487		kfree(ph2c);
488		return;
489	}
490	init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
491	psetop->mode = (u8)networktype;
492	r8712_enqueue_cmd(pcmdpriv, ph2c);
493}
494
495void r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key)
496{
497	struct cmd_obj *ph2c;
498	struct set_stakey_parm *psetstakey_para;
499	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
500	struct set_stakey_rsp *psetstakey_rsp = NULL;
501	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
502	struct security_priv *psecuritypriv = &padapter->securitypriv;
503	struct sta_info *sta = (struct sta_info *)psta;
504
505	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
506	if (!ph2c)
507		return;
508	psetstakey_para = kmalloc(sizeof(*psetstakey_para), GFP_ATOMIC);
509	if (!psetstakey_para) {
510		kfree(ph2c);
511		return;
512	}
513	psetstakey_rsp = kmalloc(sizeof(*psetstakey_rsp), GFP_ATOMIC);
514	if (!psetstakey_rsp) {
515		kfree(ph2c);
516		kfree(psetstakey_para);
517		return;
518	}
519	init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
520	ph2c->rsp = (u8 *)psetstakey_rsp;
521	ph2c->rspsz = sizeof(struct set_stakey_rsp);
522	ether_addr_copy(psetstakey_para->addr, sta->hwaddr);
523	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
524		psetstakey_para->algorithm = (unsigned char)
525					    psecuritypriv->PrivacyAlgrthm;
526	else
527		GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, false);
528	if (unicast_key)
529		memcpy(&psetstakey_para->key, &sta->x_UncstKey, 16);
530	else
531		memcpy(&psetstakey_para->key, &psecuritypriv->XGrpKey[psecuritypriv->XGrpKeyid - 1].
532		       skey, 16);
533	r8712_enqueue_cmd(pcmdpriv, ph2c);
534}
535
536void r8712_setMacAddr_cmd(struct _adapter *padapter, const u8 *mac_addr)
537{
538	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
539	struct cmd_obj *ph2c;
540	struct SetMacAddr_param	*psetMacAddr_para;
541
542	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
543	if (!ph2c)
544		return;
545	psetMacAddr_para = kmalloc(sizeof(*psetMacAddr_para), GFP_ATOMIC);
546	if (!psetMacAddr_para) {
547		kfree(ph2c);
548		return;
549	}
550	init_h2fwcmd_w_parm_no_rsp(ph2c, psetMacAddr_para, _SetMacAddress_CMD_);
551	ether_addr_copy(psetMacAddr_para->MacAddr, mac_addr);
552	r8712_enqueue_cmd(pcmdpriv, ph2c);
553}
554
555void r8712_addbareq_cmd(struct _adapter *padapter, u8 tid)
556{
557	struct cmd_priv		*pcmdpriv = &padapter->cmdpriv;
558	struct cmd_obj		*ph2c;
559	struct addBaReq_parm	*paddbareq_parm;
560
561	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
562	if (!ph2c)
563		return;
564	paddbareq_parm = kmalloc(sizeof(*paddbareq_parm), GFP_ATOMIC);
565	if (!paddbareq_parm) {
566		kfree(ph2c);
567		return;
568	}
569	paddbareq_parm->tid = tid;
570	init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq));
571	r8712_enqueue_cmd_ex(pcmdpriv, ph2c);
572}
573
574void r8712_wdg_wk_cmd(struct _adapter *padapter)
575{
576	struct cmd_obj *ph2c;
577	struct drvint_cmd_parm  *pdrvintcmd_param;
578	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
579
580	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
581	if (!ph2c)
582		return;
583	pdrvintcmd_param = kmalloc(sizeof(*pdrvintcmd_param), GFP_ATOMIC);
584	if (!pdrvintcmd_param) {
585		kfree(ph2c);
586		return;
587	}
588	pdrvintcmd_param->i_cid = WDG_WK_CID;
589	pdrvintcmd_param->sz = 0;
590	pdrvintcmd_param->pbuf = NULL;
591	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvintcmd_param, _DRV_INT_CMD_);
592	r8712_enqueue_cmd_ex(pcmdpriv, ph2c);
593}
594
595void r8712_survey_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd)
596{
597	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
598
599	if (pcmd->res != H2C_SUCCESS)
600		clr_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
601	r8712_free_cmd_obj(pcmd);
602}
603
604void r8712_disassoc_cmd_callback(struct _adapter *padapter,
605				 struct cmd_obj *pcmd)
606{
607	unsigned long irqL;
608	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
609
610	if (pcmd->res != H2C_SUCCESS) {
611		spin_lock_irqsave(&pmlmepriv->lock, irqL);
612		set_fwstate(pmlmepriv, _FW_LINKED);
613		spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
614		return;
615	}
616	r8712_free_cmd_obj(pcmd);
617}
618
619void r8712_joinbss_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd)
620{
621	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
622
623	if (pcmd->res != H2C_SUCCESS)
624		mod_timer(&pmlmepriv->assoc_timer, jiffies + msecs_to_jiffies(1));
625	r8712_free_cmd_obj(pcmd);
626}
627
628void r8712_createbss_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd)
629{
630	unsigned long irqL;
631	struct sta_info *psta = NULL;
632	struct wlan_network *pwlan = NULL;
633	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
634	struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf;
635	struct wlan_network *tgt_network = &(pmlmepriv->cur_network);
636
637	if (pcmd->res != H2C_SUCCESS)
638		mod_timer(&pmlmepriv->assoc_timer, jiffies + msecs_to_jiffies(1));
639	del_timer(&pmlmepriv->assoc_timer);
640#ifdef __BIG_ENDIAN
641	/* endian_convert */
642	pnetwork->Length = le32_to_cpu(pnetwork->Length);
643	pnetwork->Ssid.SsidLength = le32_to_cpu(pnetwork->Ssid.SsidLength);
644	pnetwork->Privacy = le32_to_cpu(pnetwork->Privacy);
645	pnetwork->Rssi = le32_to_cpu(pnetwork->Rssi);
646	pnetwork->NetworkTypeInUse = le32_to_cpu(pnetwork->NetworkTypeInUse);
647	pnetwork->Configuration.ATIMWindow = le32_to_cpu(pnetwork->Configuration.ATIMWindow);
648	pnetwork->Configuration.DSConfig = le32_to_cpu(pnetwork->Configuration.DSConfig);
649	pnetwork->Configuration.FHConfig.DwellTime = le32_to_cpu(pnetwork->Configuration.FHConfig.DwellTime);
650	pnetwork->Configuration.FHConfig.HopPattern = le32_to_cpu(pnetwork->Configuration.FHConfig.HopPattern);
651	pnetwork->Configuration.FHConfig.HopSet = le32_to_cpu(pnetwork->Configuration.FHConfig.HopSet);
652	pnetwork->Configuration.FHConfig.Length = le32_to_cpu(pnetwork->Configuration.FHConfig.Length);
653	pnetwork->Configuration.Length = le32_to_cpu(pnetwork->Configuration.Length);
654	pnetwork->InfrastructureMode = le32_to_cpu(pnetwork->InfrastructureMode);
655	pnetwork->IELength = le32_to_cpu(pnetwork->IELength);
656#endif
657	spin_lock_irqsave(&pmlmepriv->lock, irqL);
658	if ((pmlmepriv->fw_state) & WIFI_AP_STATE) {
659		psta = r8712_get_stainfo(&padapter->stapriv, pnetwork->MacAddress);
660		if (!psta) {
661			psta = r8712_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress);
662			if (!psta)
663				goto createbss_cmd_fail;
664		}
665		r8712_indicate_connect(padapter);
666	} else {
667		pwlan = _r8712_alloc_network(pmlmepriv);
668		if (!pwlan) {
669			pwlan = r8712_get_oldest_wlan_network(&pmlmepriv->scanned_queue);
670			if (!pwlan)
671				goto createbss_cmd_fail;
672			pwlan->last_scanned = jiffies;
673		} else {
674			list_add_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue);
675		}
676		pnetwork->Length = r8712_get_wlan_bssid_ex_sz(pnetwork);
677		memcpy(&(pwlan->network), pnetwork, pnetwork->Length);
678		pwlan->fixed = true;
679		memcpy(&tgt_network->network, pnetwork, (r8712_get_wlan_bssid_ex_sz(pnetwork)));
680		if (pmlmepriv->fw_state & _FW_UNDER_LINKING)
681			pmlmepriv->fw_state ^= _FW_UNDER_LINKING;
682		/*
683		 * we will set _FW_LINKED when there is one more sat to
684		 * join us (stassoc_event_callback)
685		 */
686	}
687createbss_cmd_fail:
688	spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
689	r8712_free_cmd_obj(pcmd);
690}
691
692void r8712_setstaKey_cmdrsp_callback(struct _adapter *padapter, struct cmd_obj *pcmd)
693{
694	struct sta_priv *pstapriv = &padapter->stapriv;
695	struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *) (pcmd->rsp);
696	struct sta_info *psta = r8712_get_stainfo(pstapriv, psetstakey_rsp->addr);
697
698	if (!psta)
699		goto exit;
700	psta->aid = psta->mac_id = psetstakey_rsp->keyid; /*CAM_ID(CAM_ENTRY)*/
701exit:
702	r8712_free_cmd_obj(pcmd);
703}
704
705void r8712_setassocsta_cmdrsp_callback(struct _adapter *padapter,
706				       struct cmd_obj *pcmd)
707{
708	unsigned long	irqL;
709	struct sta_priv *pstapriv = &padapter->stapriv;
710	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
711	struct set_assocsta_parm *passocsta_parm = (struct set_assocsta_parm *)(pcmd->parmbuf);
712	struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *) (pcmd->rsp);
713	struct sta_info *psta = r8712_get_stainfo(pstapriv, passocsta_parm->addr);
714
715	if (!psta)
716		return;
717	psta->aid = psta->mac_id = passocsta_rsp->cam_id;
718	spin_lock_irqsave(&pmlmepriv->lock, irqL);
719	if ((check_fwstate(pmlmepriv, WIFI_MP_STATE)) && (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)))
720		pmlmepriv->fw_state ^= _FW_UNDER_LINKING;
721	set_fwstate(pmlmepriv, _FW_LINKED);
722	spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
723	r8712_free_cmd_obj(pcmd);
724}
725
726void r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl, u32 tryPktCnt,
727				u32 tryPktInterval, u32 firstStageTO)
728{
729	struct cmd_obj *ph2c;
730	struct DisconnectCtrlEx_param *param;
731	struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
732
733	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
734	if (!ph2c)
735		return;
736	param = kzalloc(sizeof(*param), GFP_ATOMIC);
737	if (!param) {
738		kfree(ph2c);
739		return;
740	}
741
742	param->EnableDrvCtrl = (unsigned char)enableDrvCtrl;
743	param->TryPktCnt = (unsigned char)tryPktCnt;
744	param->TryPktInterval = (unsigned char)tryPktInterval;
745	param->FirstStageTO = (unsigned int)firstStageTO;
746
747	init_h2fwcmd_w_parm_no_rsp(ph2c, param, GEN_CMD_CODE(_DisconnectCtrlEx));
748	r8712_enqueue_cmd(pcmdpriv, ph2c);
749}
750