1 /******************************************************************************
2  * rtl871x_cmd.c
3  *
4  * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
5  * Linux device driver for RTL8192SU
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of version 2 of the GNU General Public License as
9  * published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19  *
20  * Modifications for inclusion into the Linux staging tree are
21  * Copyright(c) 2010 Larry Finger. All rights reserved.
22  *
23  * Contact information:
24  * WLAN FAE <wlanfae@realtek.com>
25  * Larry Finger <Larry.Finger@lwfinger.net>
26  *
27  ******************************************************************************/
28 
29 #define _RTL871X_CMD_C_
30 
31 #include <linux/compiler.h>
32 #include <linux/kernel.h>
33 #include <linux/errno.h>
34 #include <linux/slab.h>
35 #include <linux/module.h>
36 #include <linux/kref.h>
37 #include <linux/netdevice.h>
38 #include <linux/skbuff.h>
39 #include <linux/usb.h>
40 #include <linux/usb/ch9.h>
41 #include <linux/circ_buf.h>
42 #include <linux/uaccess.h>
43 #include <asm/byteorder.h>
44 #include <linux/atomic.h>
45 #include <linux/semaphore.h>
46 #include <linux/rtnetlink.h>
47 
48 #include "osdep_service.h"
49 #include "drv_types.h"
50 #include "recv_osdep.h"
51 #include "mlme_osdep.h"
52 
53 /*
54  * Caller and the r8712_cmd_thread can protect cmd_q by spin_lock.
55  * No irqsave is necessary.
56  */
57 
58 static sint _init_cmd_priv(struct cmd_priv *pcmdpriv)
59 {
60 	init_completion(&pcmdpriv->cmd_queue_comp);
61 	init_completion(&pcmdpriv->terminate_cmdthread_comp);
62 
63 	_init_queue(&(pcmdpriv->cmd_queue));
64 
65 	/* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
66 	pcmdpriv->cmd_seq = 1;
67 	pcmdpriv->cmd_allocated_buf = kmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ,
68 					      GFP_ATOMIC);
69 	if (!pcmdpriv->cmd_allocated_buf)
70 		return _FAIL;
71 	pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf  +  CMDBUFF_ALIGN_SZ -
72 			    ((addr_t)(pcmdpriv->cmd_allocated_buf) &
73 			    (CMDBUFF_ALIGN_SZ - 1));
74 	pcmdpriv->rsp_allocated_buf = kmalloc(MAX_RSPSZ + 4, GFP_ATOMIC);
75 	if (!pcmdpriv->rsp_allocated_buf) {
76 		kfree(pcmdpriv->cmd_allocated_buf);
77 		pcmdpriv->cmd_allocated_buf = NULL;
78 		return _FAIL;
79 	}
80 	pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf  +  4 -
81 			    ((addr_t)(pcmdpriv->rsp_allocated_buf) & 3);
82 	pcmdpriv->cmd_issued_cnt = 0;
83 	pcmdpriv->cmd_done_cnt = 0;
84 	pcmdpriv->rsp_cnt = 0;
85 	return _SUCCESS;
86 }
87 
88 static sint _init_evt_priv(struct evt_priv *pevtpriv)
89 {
90 	/* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
91 	pevtpriv->event_seq = 0;
92 	pevtpriv->evt_allocated_buf = kmalloc(MAX_EVTSZ + 4, GFP_ATOMIC);
93 
94 	if (!pevtpriv->evt_allocated_buf)
95 		return _FAIL;
96 	pevtpriv->evt_buf = pevtpriv->evt_allocated_buf  +  4 -
97 			    ((addr_t)(pevtpriv->evt_allocated_buf) & 3);
98 	pevtpriv->evt_done_cnt = 0;
99 	return _SUCCESS;
100 }
101 
102 static void _free_evt_priv(struct evt_priv *pevtpriv)
103 {
104 	kfree(pevtpriv->evt_allocated_buf);
105 }
106 
107 static void _free_cmd_priv(struct cmd_priv *pcmdpriv)
108 {
109 	if (pcmdpriv) {
110 		kfree(pcmdpriv->cmd_allocated_buf);
111 		kfree(pcmdpriv->rsp_allocated_buf);
112 	}
113 }
114 
115 /*
116  * Calling Context:
117  *
118  * _enqueue_cmd can only be called between kernel thread,
119  * since only spin_lock is used.
120  *
121  * ISR/Call-Back functions can't call this sub-function.
122  *
123  */
124 
125 static sint _enqueue_cmd(struct  __queue *queue, struct cmd_obj *obj)
126 {
127 	unsigned long irqL;
128 
129 	if (!obj)
130 		return _SUCCESS;
131 	spin_lock_irqsave(&queue->lock, irqL);
132 	list_add_tail(&obj->list, &queue->queue);
133 	spin_unlock_irqrestore(&queue->lock, irqL);
134 	return _SUCCESS;
135 }
136 
137 static struct cmd_obj *_dequeue_cmd(struct  __queue *queue)
138 {
139 	unsigned long irqL;
140 	struct cmd_obj *obj;
141 
142 	spin_lock_irqsave(&queue->lock, irqL);
143 	obj = list_first_entry_or_null(&queue->queue,
144 				       struct cmd_obj, list);
145 	if (obj)
146 		list_del_init(&obj->list);
147 	spin_unlock_irqrestore(&queue->lock, irqL);
148 	return obj;
149 }
150 
151 u32 r8712_init_cmd_priv(struct cmd_priv *pcmdpriv)
152 {
153 	return _init_cmd_priv(pcmdpriv);
154 }
155 
156 u32 r8712_init_evt_priv(struct evt_priv *pevtpriv)
157 {
158 	return _init_evt_priv(pevtpriv);
159 }
160 
161 void r8712_free_evt_priv(struct evt_priv *pevtpriv)
162 {
163 	_free_evt_priv(pevtpriv);
164 }
165 
166 void r8712_free_cmd_priv(struct cmd_priv *pcmdpriv)
167 {
168 	_free_cmd_priv(pcmdpriv);
169 }
170 
171 u32 r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj)
172 {
173 	int res;
174 
175 	if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag)
176 		return _FAIL;
177 	res = _enqueue_cmd(&pcmdpriv->cmd_queue, obj);
178 	complete(&pcmdpriv->cmd_queue_comp);
179 	return res;
180 }
181 
182 u32 r8712_enqueue_cmd_ex(struct cmd_priv *pcmdpriv, struct cmd_obj *obj)
183 {
184 	unsigned long irqL;
185 	struct  __queue *queue;
186 
187 	if (!obj)
188 		return _SUCCESS;
189 	if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag)
190 		return _FAIL;
191 	queue = &pcmdpriv->cmd_queue;
192 	spin_lock_irqsave(&queue->lock, irqL);
193 	list_add_tail(&obj->list, &queue->queue);
194 	spin_unlock_irqrestore(&queue->lock, irqL);
195 	complete(&pcmdpriv->cmd_queue_comp);
196 	return _SUCCESS;
197 }
198 
199 struct cmd_obj *r8712_dequeue_cmd(struct  __queue *queue)
200 {
201 	return _dequeue_cmd(queue);
202 }
203 
204 void r8712_free_cmd_obj(struct cmd_obj *pcmd)
205 {
206 	if ((pcmd->cmdcode != _JoinBss_CMD_) &&
207 	    (pcmd->cmdcode != _CreateBss_CMD_))
208 		kfree(pcmd->parmbuf);
209 	if (pcmd->rsp != NULL) {
210 		if (pcmd->rspsz != 0)
211 			kfree(pcmd->rsp);
212 	}
213 	kfree(pcmd);
214 }
215 
216 /*
217  *	r8712_sitesurvey_cmd(~)
218  *		### NOTE:#### (!!!!)
219  *		MUST TAKE CARE THAT BEFORE CALLING THIS FUNC,
220  *		YOU SHOULD HAVE LOCKED pmlmepriv->lock
221  */
222 u8 r8712_sitesurvey_cmd(struct _adapter *padapter,
223 			struct ndis_802_11_ssid *pssid)
224 {
225 	struct cmd_obj	*ph2c;
226 	struct sitesurvey_parm	*psurveyPara;
227 	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
228 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
229 
230 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
231 	if (!ph2c)
232 		return _FAIL;
233 	psurveyPara = kmalloc(sizeof(*psurveyPara), GFP_ATOMIC);
234 	if (!psurveyPara) {
235 		kfree(ph2c);
236 		return _FAIL;
237 	}
238 	init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara,
239 				   GEN_CMD_CODE(_SiteSurvey));
240 	psurveyPara->bsslimit = cpu_to_le32(48);
241 	psurveyPara->passive_mode = cpu_to_le32(pmlmepriv->passive_mode);
242 	psurveyPara->ss_ssidlen = 0;
243 	memset(psurveyPara->ss_ssid, 0, IW_ESSID_MAX_SIZE + 1);
244 	if ((pssid != NULL) && (pssid->SsidLength)) {
245 		memcpy(psurveyPara->ss_ssid, pssid->Ssid, pssid->SsidLength);
246 		psurveyPara->ss_ssidlen = cpu_to_le32(pssid->SsidLength);
247 	}
248 	set_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
249 	r8712_enqueue_cmd(pcmdpriv, ph2c);
250 	mod_timer(&pmlmepriv->scan_to_timer,
251 		  jiffies + msecs_to_jiffies(SCANNING_TIMEOUT));
252 	padapter->ledpriv.LedControlHandler(padapter, LED_CTL_SITE_SURVEY);
253 	padapter->blnEnableRxFF0Filter = 0;
254 	return _SUCCESS;
255 }
256 
257 u8 r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset)
258 {
259 	struct cmd_obj		*ph2c;
260 	struct setdatarate_parm	*pbsetdataratepara;
261 	struct cmd_priv		*pcmdpriv = &padapter->cmdpriv;
262 
263 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
264 	if (!ph2c)
265 		return _FAIL;
266 	pbsetdataratepara = kmalloc(sizeof(*pbsetdataratepara), GFP_ATOMIC);
267 	if (!pbsetdataratepara) {
268 		kfree(ph2c);
269 		return _FAIL;
270 	}
271 	init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara,
272 				   GEN_CMD_CODE(_SetDataRate));
273 	pbsetdataratepara->mac_id = 5;
274 	memcpy(pbsetdataratepara->datarates, rateset, NumRates);
275 	r8712_enqueue_cmd(pcmdpriv, ph2c);
276 	return _SUCCESS;
277 }
278 
279 u8 r8712_set_chplan_cmd(struct _adapter *padapter, int chplan)
280 {
281 	struct cmd_obj *ph2c;
282 	struct SetChannelPlan_param *psetchplanpara;
283 	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
284 
285 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
286 	if (!ph2c)
287 		return _FAIL;
288 	psetchplanpara = kmalloc(sizeof(*psetchplanpara), GFP_ATOMIC);
289 	if (!psetchplanpara) {
290 		kfree(ph2c);
291 		return _FAIL;
292 	}
293 	init_h2fwcmd_w_parm_no_rsp(ph2c, psetchplanpara,
294 				GEN_CMD_CODE(_SetChannelPlan));
295 	psetchplanpara->ChannelPlan = chplan;
296 	r8712_enqueue_cmd(pcmdpriv, ph2c);
297 	return _SUCCESS;
298 }
299 
300 u8 r8712_setbasicrate_cmd(struct _adapter *padapter, u8 *rateset)
301 {
302 	struct cmd_obj *ph2c;
303 	struct setbasicrate_parm *pssetbasicratepara;
304 	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
305 
306 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
307 	if (!ph2c)
308 		return _FAIL;
309 	pssetbasicratepara = kmalloc(sizeof(*pssetbasicratepara), GFP_ATOMIC);
310 	if (!pssetbasicratepara) {
311 		kfree(ph2c);
312 		return _FAIL;
313 	}
314 	init_h2fwcmd_w_parm_no_rsp(ph2c, pssetbasicratepara,
315 		_SetBasicRate_CMD_);
316 	memcpy(pssetbasicratepara->basicrates, rateset, NumRates);
317 	r8712_enqueue_cmd(pcmdpriv, ph2c);
318 	return _SUCCESS;
319 }
320 
321 u8 r8712_setfwdig_cmd(struct _adapter *padapter, u8 type)
322 {
323 	struct cmd_obj *ph2c;
324 	struct writePTM_parm *pwriteptmparm;
325 	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
326 
327 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
328 	if (!ph2c)
329 		return _FAIL;
330 	pwriteptmparm = kmalloc(sizeof(*pwriteptmparm), GFP_ATOMIC);
331 	if (!pwriteptmparm) {
332 		kfree(ph2c);
333 		return _FAIL;
334 	}
335 	init_h2fwcmd_w_parm_no_rsp(ph2c, pwriteptmparm, GEN_CMD_CODE(_SetDIG));
336 	pwriteptmparm->type = type;
337 	r8712_enqueue_cmd(pcmdpriv, ph2c);
338 	return _SUCCESS;
339 }
340 
341 u8 r8712_setfwra_cmd(struct _adapter *padapter, u8 type)
342 {
343 	struct cmd_obj *ph2c;
344 	struct writePTM_parm *pwriteptmparm;
345 	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
346 
347 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
348 	if (!ph2c)
349 		return _FAIL;
350 	pwriteptmparm = kmalloc(sizeof(*pwriteptmparm), GFP_ATOMIC);
351 	if (!pwriteptmparm) {
352 		kfree(ph2c);
353 		return _FAIL;
354 	}
355 	init_h2fwcmd_w_parm_no_rsp(ph2c, pwriteptmparm, GEN_CMD_CODE(_SetRA));
356 	pwriteptmparm->type = type;
357 	r8712_enqueue_cmd(pcmdpriv, ph2c);
358 	return _SUCCESS;
359 }
360 
361 u8 r8712_setrfreg_cmd(struct _adapter  *padapter, u8 offset, u32 val)
362 {
363 	struct cmd_obj *ph2c;
364 	struct writeRF_parm *pwriterfparm;
365 	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
366 
367 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
368 	if (!ph2c)
369 		return _FAIL;
370 	pwriterfparm = kmalloc(sizeof(*pwriterfparm), GFP_ATOMIC);
371 	if (!pwriterfparm) {
372 		kfree(ph2c);
373 		return _FAIL;
374 	}
375 	init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg));
376 	pwriterfparm->offset = offset;
377 	pwriterfparm->value = val;
378 	r8712_enqueue_cmd(pcmdpriv, ph2c);
379 	return _SUCCESS;
380 }
381 
382 u8 r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval)
383 {
384 	struct cmd_obj *ph2c;
385 	struct readRF_parm *prdrfparm;
386 	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
387 
388 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
389 	if (!ph2c)
390 		return _FAIL;
391 	prdrfparm = kmalloc(sizeof(*prdrfparm), GFP_ATOMIC);
392 	if (!prdrfparm) {
393 		kfree(ph2c);
394 		return _FAIL;
395 	}
396 	INIT_LIST_HEAD(&ph2c->list);
397 	ph2c->cmdcode = GEN_CMD_CODE(_GetRFReg);
398 	ph2c->parmbuf = (unsigned char *)prdrfparm;
399 	ph2c->cmdsz =  sizeof(struct readRF_parm);
400 	ph2c->rsp = pval;
401 	ph2c->rspsz = sizeof(struct readRF_rsp);
402 	prdrfparm->offset = offset;
403 	r8712_enqueue_cmd(pcmdpriv, ph2c);
404 	return _SUCCESS;
405 }
406 
407 void r8712_getbbrfreg_cmdrsp_callback(struct _adapter *padapter,
408 				      struct cmd_obj *pcmd)
409 {
410 	kfree(pcmd->parmbuf);
411 	kfree(pcmd);
412 	padapter->mppriv.workparam.bcompleted = true;
413 }
414 
415 void r8712_readtssi_cmdrsp_callback(struct _adapter *padapter,
416 				struct cmd_obj *pcmd)
417 {
418 	kfree(pcmd->parmbuf);
419 	kfree(pcmd);
420 
421 	padapter->mppriv.workparam.bcompleted = true;
422 }
423 
424 u8 r8712_createbss_cmd(struct _adapter *padapter)
425 {
426 	struct cmd_obj *pcmd;
427 	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
428 	struct wlan_bssid_ex *pdev_network =
429 				 &padapter->registrypriv.dev_network;
430 
431 	padapter->ledpriv.LedControlHandler(padapter, LED_CTL_START_TO_LINK);
432 	pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC);
433 	if (!pcmd)
434 		return _FAIL;
435 	INIT_LIST_HEAD(&pcmd->list);
436 	pcmd->cmdcode = _CreateBss_CMD_;
437 	pcmd->parmbuf = (unsigned char *)pdev_network;
438 	pcmd->cmdsz = r8712_get_wlan_bssid_ex_sz(pdev_network);
439 	pcmd->rsp = NULL;
440 	pcmd->rspsz = 0;
441 	/* notes: translate IELength & Length after assign to cmdsz; */
442 	pdev_network->Length = pcmd->cmdsz;
443 	pdev_network->IELength = pdev_network->IELength;
444 	pdev_network->Ssid.SsidLength =	pdev_network->Ssid.SsidLength;
445 	r8712_enqueue_cmd(pcmdpriv, pcmd);
446 	return _SUCCESS;
447 }
448 
449 u8 r8712_joinbss_cmd(struct _adapter  *padapter, struct wlan_network *pnetwork)
450 {
451 	struct wlan_bssid_ex *psecnetwork;
452 	struct cmd_obj		*pcmd;
453 	struct cmd_priv		*pcmdpriv = &padapter->cmdpriv;
454 	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
455 	struct qos_priv		*pqospriv = &pmlmepriv->qospriv;
456 	struct security_priv	*psecuritypriv = &padapter->securitypriv;
457 	struct registry_priv	*pregistrypriv = &padapter->registrypriv;
458 	enum NDIS_802_11_NETWORK_INFRASTRUCTURE ndis_network_mode =
459 		pnetwork->network.InfrastructureMode;
460 
461 	padapter->ledpriv.LedControlHandler(padapter, LED_CTL_START_TO_LINK);
462 	pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC);
463 	if (!pcmd)
464 		return _FAIL;
465 
466 	/* for hidden ap to set fw_state here */
467 	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) !=
468 	    true) {
469 		switch (ndis_network_mode) {
470 		case Ndis802_11IBSS:
471 			pmlmepriv->fw_state |= WIFI_ADHOC_STATE;
472 			break;
473 		case Ndis802_11Infrastructure:
474 			pmlmepriv->fw_state |= WIFI_STATION_STATE;
475 			break;
476 		case Ndis802_11APMode:
477 		case Ndis802_11AutoUnknown:
478 		case Ndis802_11InfrastructureMax:
479 			break;
480 		}
481 	}
482 	psecnetwork = &psecuritypriv->sec_bss;
483 	if (!psecnetwork) {
484 		kfree(pcmd);
485 		return _FAIL;
486 	}
487 	memcpy(psecnetwork, &pnetwork->network, sizeof(*psecnetwork));
488 	psecuritypriv->authenticator_ie[0] = (unsigned char)
489 					     psecnetwork->IELength;
490 	if ((psecnetwork->IELength - 12) < (256 - 1))
491 		memcpy(&psecuritypriv->authenticator_ie[1],
492 			&psecnetwork->IEs[12], psecnetwork->IELength - 12);
493 	else
494 		memcpy(&psecuritypriv->authenticator_ie[1],
495 			&psecnetwork->IEs[12], (256 - 1));
496 	psecnetwork->IELength = 0;
497 	/*
498 	 * If the driver wants to use the bssid to create the connection.
499 	 * If not, we copy the connecting AP's MAC address to it so that
500 	 * the driver just has the bssid information for PMKIDList searching.
501 	 */
502 	if (!pmlmepriv->assoc_by_bssid)
503 		ether_addr_copy(&pmlmepriv->assoc_bssid[0],
504 				&pnetwork->network.MacAddress[0]);
505 	psecnetwork->IELength = r8712_restruct_sec_ie(padapter,
506 						&pnetwork->network.IEs[0],
507 						&psecnetwork->IEs[0],
508 						pnetwork->network.IELength);
509 	pqospriv->qos_option = 0;
510 	if (pregistrypriv->wmm_enable) {
511 		u32 tmp_len;
512 
513 		tmp_len = r8712_restruct_wmm_ie(padapter,
514 					  &pnetwork->network.IEs[0],
515 					  &psecnetwork->IEs[0],
516 					  pnetwork->network.IELength,
517 					  psecnetwork->IELength);
518 		if (psecnetwork->IELength != tmp_len) {
519 			psecnetwork->IELength = tmp_len;
520 			pqospriv->qos_option = 1; /* WMM IE in beacon */
521 		} else {
522 			pqospriv->qos_option = 0; /* no WMM IE in beacon */
523 		}
524 	}
525 	if (pregistrypriv->ht_enable) {
526 		/*
527 		 * For WEP mode, we will use the bg mode to do the connection
528 		 * to avoid some IOT issues, especially for Realtek 8192u
529 		 * SoftAP.
530 		 */
531 		if ((padapter->securitypriv.PrivacyAlgrthm != _WEP40_) &&
532 		    (padapter->securitypriv.PrivacyAlgrthm != _WEP104_)) {
533 			/* restructure_ht_ie */
534 			r8712_restructure_ht_ie(padapter,
535 						&pnetwork->network.IEs[0],
536 						&psecnetwork->IEs[0],
537 						pnetwork->network.IELength,
538 						&psecnetwork->IELength);
539 		}
540 	}
541 	psecuritypriv->supplicant_ie[0] = (u8)psecnetwork->IELength;
542 	if (psecnetwork->IELength < 255)
543 		memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0],
544 			psecnetwork->IELength);
545 	else
546 		memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0],
547 			255);
548 	/* get cmdsz before endian conversion */
549 	pcmd->cmdsz = r8712_get_wlan_bssid_ex_sz(psecnetwork);
550 #ifdef __BIG_ENDIAN
551 	/* wlan_network endian conversion */
552 	psecnetwork->Length = cpu_to_le32(psecnetwork->Length);
553 	psecnetwork->Ssid.SsidLength = cpu_to_le32(
554 				       psecnetwork->Ssid.SsidLength);
555 	psecnetwork->Privacy = cpu_to_le32(psecnetwork->Privacy);
556 	psecnetwork->Rssi = cpu_to_le32(psecnetwork->Rssi);
557 	psecnetwork->NetworkTypeInUse = cpu_to_le32(
558 					psecnetwork->NetworkTypeInUse);
559 	psecnetwork->Configuration.ATIMWindow = cpu_to_le32(
560 				psecnetwork->Configuration.ATIMWindow);
561 	psecnetwork->Configuration.BeaconPeriod = cpu_to_le32(
562 				 psecnetwork->Configuration.BeaconPeriod);
563 	psecnetwork->Configuration.DSConfig = cpu_to_le32(
564 				psecnetwork->Configuration.DSConfig);
565 	psecnetwork->Configuration.FHConfig.DwellTime = cpu_to_le32(
566 				psecnetwork->Configuration.FHConfig.DwellTime);
567 	psecnetwork->Configuration.FHConfig.HopPattern = cpu_to_le32(
568 				psecnetwork->Configuration.FHConfig.HopPattern);
569 	psecnetwork->Configuration.FHConfig.HopSet = cpu_to_le32(
570 				psecnetwork->Configuration.FHConfig.HopSet);
571 	psecnetwork->Configuration.FHConfig.Length = cpu_to_le32(
572 				psecnetwork->Configuration.FHConfig.Length);
573 	psecnetwork->Configuration.Length = cpu_to_le32(
574 				psecnetwork->Configuration.Length);
575 	psecnetwork->InfrastructureMode = cpu_to_le32(
576 				psecnetwork->InfrastructureMode);
577 	psecnetwork->IELength = cpu_to_le32(psecnetwork->IELength);
578 #endif
579 	INIT_LIST_HEAD(&pcmd->list);
580 	pcmd->cmdcode = _JoinBss_CMD_;
581 	pcmd->parmbuf = (unsigned char *)psecnetwork;
582 	pcmd->rsp = NULL;
583 	pcmd->rspsz = 0;
584 	r8712_enqueue_cmd(pcmdpriv, pcmd);
585 	return _SUCCESS;
586 }
587 
588 u8 r8712_disassoc_cmd(struct _adapter *padapter) /* for sta_mode */
589 {
590 	struct cmd_obj *pdisconnect_cmd;
591 	struct disconnect_parm *pdisconnect;
592 	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
593 
594 	pdisconnect_cmd = kmalloc(sizeof(*pdisconnect_cmd), GFP_ATOMIC);
595 	if (!pdisconnect_cmd)
596 		return _FAIL;
597 	pdisconnect = kmalloc(sizeof(*pdisconnect), GFP_ATOMIC);
598 	if (!pdisconnect) {
599 		kfree(pdisconnect_cmd);
600 		return _FAIL;
601 	}
602 	init_h2fwcmd_w_parm_no_rsp(pdisconnect_cmd, pdisconnect,
603 				   _DisConnect_CMD_);
604 	r8712_enqueue_cmd(pcmdpriv, pdisconnect_cmd);
605 	return _SUCCESS;
606 }
607 
608 u8 r8712_setopmode_cmd(struct _adapter *padapter,
609 		 enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype)
610 {
611 	struct cmd_obj *ph2c;
612 	struct setopmode_parm *psetop;
613 
614 	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
615 
616 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
617 	if (!ph2c)
618 		return _FAIL;
619 	psetop = kmalloc(sizeof(*psetop), GFP_ATOMIC);
620 	if (!psetop) {
621 		kfree(ph2c);
622 		return _FAIL;
623 	}
624 	init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
625 	psetop->mode = (u8)networktype;
626 	r8712_enqueue_cmd(pcmdpriv, ph2c);
627 	return _SUCCESS;
628 }
629 
630 u8 r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key)
631 {
632 	struct cmd_obj *ph2c;
633 	struct set_stakey_parm *psetstakey_para;
634 	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
635 	struct set_stakey_rsp *psetstakey_rsp = NULL;
636 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
637 	struct security_priv *psecuritypriv = &padapter->securitypriv;
638 	struct sta_info *sta = (struct sta_info *)psta;
639 
640 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
641 	if (!ph2c)
642 		return _FAIL;
643 	psetstakey_para = kmalloc(sizeof(*psetstakey_para), GFP_ATOMIC);
644 	if (!psetstakey_para) {
645 		kfree(ph2c);
646 		return _FAIL;
647 	}
648 	psetstakey_rsp = kmalloc(sizeof(*psetstakey_rsp), GFP_ATOMIC);
649 	if (!psetstakey_rsp) {
650 		kfree(ph2c);
651 		kfree(psetstakey_para);
652 		return _FAIL;
653 	}
654 	init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
655 	ph2c->rsp = (u8 *) psetstakey_rsp;
656 	ph2c->rspsz = sizeof(struct set_stakey_rsp);
657 	ether_addr_copy(psetstakey_para->addr, sta->hwaddr);
658 	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
659 		psetstakey_para->algorithm = (unsigned char)
660 					    psecuritypriv->PrivacyAlgrthm;
661 	else
662 		GET_ENCRY_ALGO(psecuritypriv, sta,
663 			       psetstakey_para->algorithm, false);
664 	if (unicast_key)
665 		memcpy(&psetstakey_para->key, &sta->x_UncstKey, 16);
666 	else
667 		memcpy(&psetstakey_para->key,
668 			&psecuritypriv->XGrpKey[
669 			psecuritypriv->XGrpKeyid - 1]. skey, 16);
670 	r8712_enqueue_cmd(pcmdpriv, ph2c);
671 	return _SUCCESS;
672 }
673 
674 u8 r8712_setrfintfs_cmd(struct _adapter *padapter, u8 mode)
675 {
676 	struct cmd_obj *ph2c;
677 	struct setrfintfs_parm *psetrfintfsparm;
678 	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
679 
680 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
681 	if (!ph2c)
682 		return _FAIL;
683 	psetrfintfsparm = kmalloc(sizeof(*psetrfintfsparm), GFP_ATOMIC);
684 	if (!psetrfintfsparm) {
685 		kfree(ph2c);
686 		return _FAIL;
687 	}
688 	init_h2fwcmd_w_parm_no_rsp(ph2c, psetrfintfsparm,
689 				   GEN_CMD_CODE(_SetRFIntFs));
690 	psetrfintfsparm->rfintfs = mode;
691 	r8712_enqueue_cmd(pcmdpriv, ph2c);
692 	return _SUCCESS;
693 }
694 
695 u8 r8712_setrttbl_cmd(struct _adapter *padapter,
696 		      struct setratable_parm *prate_table)
697 {
698 	struct cmd_obj *ph2c;
699 	struct setratable_parm *psetrttblparm;
700 	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
701 
702 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
703 	if (!ph2c)
704 		return _FAIL;
705 	psetrttblparm = kmalloc(sizeof(*psetrttblparm), GFP_ATOMIC);
706 	if (!psetrttblparm) {
707 		kfree(ph2c);
708 		return _FAIL;
709 	}
710 	init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm,
711 				   GEN_CMD_CODE(_SetRaTable));
712 	memcpy(psetrttblparm, prate_table, sizeof(struct setratable_parm));
713 	r8712_enqueue_cmd(pcmdpriv, ph2c);
714 	return _SUCCESS;
715 }
716 
717 u8 r8712_setMacAddr_cmd(struct _adapter *padapter, u8 *mac_addr)
718 {
719 	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
720 	struct cmd_obj *ph2c;
721 	struct SetMacAddr_param	*psetMacAddr_para;
722 
723 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
724 	if (!ph2c)
725 		return _FAIL;
726 	psetMacAddr_para = kmalloc(sizeof(*psetMacAddr_para), GFP_ATOMIC);
727 	if (!psetMacAddr_para) {
728 		kfree(ph2c);
729 		return _FAIL;
730 	}
731 	init_h2fwcmd_w_parm_no_rsp(ph2c, psetMacAddr_para,
732 				   _SetMacAddress_CMD_);
733 	ether_addr_copy(psetMacAddr_para->MacAddr, mac_addr);
734 	r8712_enqueue_cmd(pcmdpriv, ph2c);
735 	return _SUCCESS;
736 }
737 
738 u8 r8712_setassocsta_cmd(struct _adapter *padapter, u8 *mac_addr)
739 {
740 	struct cmd_priv			*pcmdpriv = &padapter->cmdpriv;
741 	struct cmd_obj			*ph2c;
742 	struct set_assocsta_parm	*psetassocsta_para;
743 	struct set_assocsta_rsp		*psetassocsta_rsp = NULL;
744 
745 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
746 	if (!ph2c)
747 		return _FAIL;
748 	psetassocsta_para = kmalloc(sizeof(*psetassocsta_para), GFP_ATOMIC);
749 	if (!psetassocsta_para) {
750 		kfree(ph2c);
751 		return _FAIL;
752 	}
753 	psetassocsta_rsp = kmalloc(sizeof(*psetassocsta_rsp), GFP_ATOMIC);
754 	if (!psetassocsta_rsp) {
755 		kfree(ph2c);
756 		kfree(psetassocsta_para);
757 		return _FAIL;
758 	}
759 	init_h2fwcmd_w_parm_no_rsp(ph2c, psetassocsta_para, _SetAssocSta_CMD_);
760 	ph2c->rsp = (u8 *) psetassocsta_rsp;
761 	ph2c->rspsz = sizeof(struct set_assocsta_rsp);
762 	ether_addr_copy(psetassocsta_para->addr, mac_addr);
763 	r8712_enqueue_cmd(pcmdpriv, ph2c);
764 	return _SUCCESS;
765 }
766 
767 u8 r8712_addbareq_cmd(struct _adapter *padapter, u8 tid)
768 {
769 	struct cmd_priv		*pcmdpriv = &padapter->cmdpriv;
770 	struct cmd_obj		*ph2c;
771 	struct addBaReq_parm	*paddbareq_parm;
772 
773 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
774 	if (!ph2c)
775 		return _FAIL;
776 	paddbareq_parm = kmalloc(sizeof(*paddbareq_parm), GFP_ATOMIC);
777 	if (!paddbareq_parm) {
778 		kfree(ph2c);
779 		return _FAIL;
780 	}
781 	paddbareq_parm->tid = tid;
782 	init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm,
783 				   GEN_CMD_CODE(_AddBAReq));
784 	r8712_enqueue_cmd_ex(pcmdpriv, ph2c);
785 	return _SUCCESS;
786 }
787 
788 u8 r8712_wdg_wk_cmd(struct _adapter *padapter)
789 {
790 	struct cmd_obj *ph2c;
791 	struct drvint_cmd_parm  *pdrvintcmd_param;
792 	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
793 
794 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
795 	if (!ph2c)
796 		return _FAIL;
797 	pdrvintcmd_param = kmalloc(sizeof(*pdrvintcmd_param), GFP_ATOMIC);
798 	if (!pdrvintcmd_param) {
799 		kfree(ph2c);
800 		return _FAIL;
801 	}
802 	pdrvintcmd_param->i_cid = WDG_WK_CID;
803 	pdrvintcmd_param->sz = 0;
804 	pdrvintcmd_param->pbuf = NULL;
805 	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvintcmd_param, _DRV_INT_CMD_);
806 	r8712_enqueue_cmd_ex(pcmdpriv, ph2c);
807 	return _SUCCESS;
808 }
809 
810 void r8712_survey_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd)
811 {
812 	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
813 
814 	if (pcmd->res != H2C_SUCCESS)
815 		clr_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
816 	r8712_free_cmd_obj(pcmd);
817 }
818 
819 void r8712_disassoc_cmd_callback(struct _adapter *padapter,
820 				 struct cmd_obj *pcmd)
821 {
822 	unsigned long irqL;
823 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
824 
825 	if (pcmd->res != H2C_SUCCESS) {
826 		spin_lock_irqsave(&pmlmepriv->lock, irqL);
827 		set_fwstate(pmlmepriv, _FW_LINKED);
828 		spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
829 		return;
830 	}
831 	r8712_free_cmd_obj(pcmd);
832 }
833 
834 void r8712_joinbss_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd)
835 {
836 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
837 
838 	if (pcmd->res != H2C_SUCCESS)
839 		mod_timer(&pmlmepriv->assoc_timer,
840 			  jiffies + msecs_to_jiffies(1));
841 	r8712_free_cmd_obj(pcmd);
842 }
843 
844 void r8712_createbss_cmd_callback(struct _adapter *padapter,
845 				  struct cmd_obj *pcmd)
846 {
847 	unsigned long irqL;
848 	struct sta_info *psta = NULL;
849 	struct wlan_network *pwlan = NULL;
850 	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
851 	struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf;
852 	struct wlan_network *tgt_network = &(pmlmepriv->cur_network);
853 
854 	if (pcmd->res != H2C_SUCCESS)
855 		mod_timer(&pmlmepriv->assoc_timer,
856 			  jiffies + msecs_to_jiffies(1));
857 	del_timer(&pmlmepriv->assoc_timer);
858 #ifdef __BIG_ENDIAN
859 	/* endian_convert */
860 	pnetwork->Length = le32_to_cpu(pnetwork->Length);
861 	pnetwork->Ssid.SsidLength = le32_to_cpu(pnetwork->Ssid.SsidLength);
862 	pnetwork->Privacy = le32_to_cpu(pnetwork->Privacy);
863 	pnetwork->Rssi = le32_to_cpu(pnetwork->Rssi);
864 	pnetwork->NetworkTypeInUse = le32_to_cpu(pnetwork->NetworkTypeInUse);
865 	pnetwork->Configuration.ATIMWindow =
866 		le32_to_cpu(pnetwork->Configuration.ATIMWindow);
867 	pnetwork->Configuration.DSConfig =
868 		le32_to_cpu(pnetwork->Configuration.DSConfig);
869 	pnetwork->Configuration.FHConfig.DwellTime =
870 		le32_to_cpu(pnetwork->Configuration.FHConfig.DwellTime);
871 	pnetwork->Configuration.FHConfig.HopPattern =
872 		le32_to_cpu(pnetwork->Configuration.FHConfig.HopPattern);
873 	pnetwork->Configuration.FHConfig.HopSet =
874 		le32_to_cpu(pnetwork->Configuration.FHConfig.HopSet);
875 	pnetwork->Configuration.FHConfig.Length =
876 		le32_to_cpu(pnetwork->Configuration.FHConfig.Length);
877 	pnetwork->Configuration.Length =
878 		le32_to_cpu(pnetwork->Configuration.Length);
879 	pnetwork->InfrastructureMode =
880 		le32_to_cpu(pnetwork->InfrastructureMode);
881 	pnetwork->IELength = le32_to_cpu(pnetwork->IELength);
882 #endif
883 	spin_lock_irqsave(&pmlmepriv->lock, irqL);
884 	if ((pmlmepriv->fw_state) & WIFI_AP_STATE) {
885 		psta = r8712_get_stainfo(&padapter->stapriv,
886 					 pnetwork->MacAddress);
887 		if (!psta) {
888 			psta = r8712_alloc_stainfo(&padapter->stapriv,
889 						   pnetwork->MacAddress);
890 			if (!psta)
891 				goto createbss_cmd_fail;
892 		}
893 		r8712_indicate_connect(padapter);
894 	} else {
895 		pwlan = _r8712_alloc_network(pmlmepriv);
896 		if (!pwlan) {
897 			pwlan = r8712_get_oldest_wlan_network(
898 				&pmlmepriv->scanned_queue);
899 			if (!pwlan)
900 				goto createbss_cmd_fail;
901 			pwlan->last_scanned = jiffies;
902 		} else {
903 			list_add_tail(&(pwlan->list),
904 					 &pmlmepriv->scanned_queue.queue);
905 		}
906 		pnetwork->Length = r8712_get_wlan_bssid_ex_sz(pnetwork);
907 		memcpy(&(pwlan->network), pnetwork, pnetwork->Length);
908 		pwlan->fixed = true;
909 		memcpy(&tgt_network->network, pnetwork,
910 			(r8712_get_wlan_bssid_ex_sz(pnetwork)));
911 		if (pmlmepriv->fw_state & _FW_UNDER_LINKING)
912 			pmlmepriv->fw_state ^= _FW_UNDER_LINKING;
913 		/*
914 		 * we will set _FW_LINKED when there is one more sat to
915 		 * join us (stassoc_event_callback)
916 		 */
917 	}
918 createbss_cmd_fail:
919 	spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
920 	r8712_free_cmd_obj(pcmd);
921 }
922 
923 void r8712_setstaKey_cmdrsp_callback(struct _adapter *padapter,
924 				     struct cmd_obj *pcmd)
925 {
926 	struct sta_priv *pstapriv = &padapter->stapriv;
927 	struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *)
928 						(pcmd->rsp);
929 	struct sta_info *psta = r8712_get_stainfo(pstapriv,
930 						  psetstakey_rsp->addr);
931 
932 	if (!psta)
933 		goto exit;
934 	psta->aid = psta->mac_id = psetstakey_rsp->keyid; /*CAM_ID(CAM_ENTRY)*/
935 exit:
936 	r8712_free_cmd_obj(pcmd);
937 }
938 
939 void r8712_setassocsta_cmdrsp_callback(struct _adapter *padapter,
940 				       struct cmd_obj *pcmd)
941 {
942 	unsigned long	irqL;
943 	struct sta_priv *pstapriv = &padapter->stapriv;
944 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
945 	struct set_assocsta_parm *passocsta_parm =
946 				(struct set_assocsta_parm *)(pcmd->parmbuf);
947 	struct set_assocsta_rsp *passocsta_rsp =
948 				(struct set_assocsta_rsp *) (pcmd->rsp);
949 	struct sta_info *psta = r8712_get_stainfo(pstapriv,
950 						  passocsta_parm->addr);
951 
952 	if (!psta)
953 		return;
954 	psta->aid = psta->mac_id = passocsta_rsp->cam_id;
955 	spin_lock_irqsave(&pmlmepriv->lock, irqL);
956 	if ((check_fwstate(pmlmepriv, WIFI_MP_STATE)) &&
957 	    (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)))
958 		pmlmepriv->fw_state ^= _FW_UNDER_LINKING;
959 	set_fwstate(pmlmepriv, _FW_LINKED);
960 	spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
961 	r8712_free_cmd_obj(pcmd);
962 }
963 
964 u8 r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
965 			u32 tryPktCnt, u32 tryPktInterval, u32 firstStageTO)
966 {
967 	struct cmd_obj *ph2c;
968 	struct DisconnectCtrlEx_param *param;
969 	struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
970 
971 	ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
972 	if (!ph2c)
973 		return _FAIL;
974 	param = kzalloc(sizeof(*param), GFP_ATOMIC);
975 	if (!param) {
976 		kfree(ph2c);
977 		return _FAIL;
978 	}
979 
980 	param->EnableDrvCtrl = (unsigned char)enableDrvCtrl;
981 	param->TryPktCnt = (unsigned char)tryPktCnt;
982 	param->TryPktInterval = (unsigned char)tryPktInterval;
983 	param->FirstStageTO = (unsigned int)firstStageTO;
984 
985 	init_h2fwcmd_w_parm_no_rsp(ph2c, param,
986 				GEN_CMD_CODE(_DisconnectCtrlEx));
987 	r8712_enqueue_cmd(pcmdpriv, ph2c);
988 	return _SUCCESS;
989 }
990