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/* 54Caller and the r8712_cmd_thread can protect cmd_q by spin_lock. 55No irqsave is necessary. 56*/ 57 58static sint _init_cmd_priv(struct cmd_priv *pcmdpriv) 59{ 60 sema_init(&(pcmdpriv->cmd_queue_sema), 0); 61 sema_init(&(pcmdpriv->terminate_cmdthread_sema), 0); 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 == NULL) 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 == NULL) 76 return _FAIL; 77 pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf + 4 - 78 ((addr_t)(pcmdpriv->rsp_allocated_buf) & 3); 79 pcmdpriv->cmd_issued_cnt = 0; 80 pcmdpriv->cmd_done_cnt = 0; 81 pcmdpriv->rsp_cnt = 0; 82 return _SUCCESS; 83} 84 85static sint _init_evt_priv(struct evt_priv *pevtpriv) 86{ 87 /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ 88 pevtpriv->event_seq = 0; 89 pevtpriv->evt_allocated_buf = kmalloc(MAX_EVTSZ + 4, GFP_ATOMIC); 90 91 if (pevtpriv->evt_allocated_buf == NULL) 92 return _FAIL; 93 pevtpriv->evt_buf = pevtpriv->evt_allocated_buf + 4 - 94 ((addr_t)(pevtpriv->evt_allocated_buf) & 3); 95 pevtpriv->evt_done_cnt = 0; 96 return _SUCCESS; 97} 98 99static void _free_evt_priv(struct evt_priv *pevtpriv) 100{ 101 kfree(pevtpriv->evt_allocated_buf); 102} 103 104static void _free_cmd_priv(struct cmd_priv *pcmdpriv) 105{ 106 if (pcmdpriv) { 107 kfree(pcmdpriv->cmd_allocated_buf); 108 kfree(pcmdpriv->rsp_allocated_buf); 109 } 110} 111 112/* 113Calling Context: 114 115_enqueue_cmd can only be called between kernel thread, 116since only spin_lock is used. 117 118ISR/Call-Back functions can't call this sub-function. 119 120*/ 121 122static sint _enqueue_cmd(struct __queue *queue, struct cmd_obj *obj) 123{ 124 unsigned long irqL; 125 126 if (obj == NULL) 127 return _SUCCESS; 128 spin_lock_irqsave(&queue->lock, irqL); 129 list_add_tail(&obj->list, &queue->queue); 130 spin_unlock_irqrestore(&queue->lock, irqL); 131 return _SUCCESS; 132} 133 134static struct cmd_obj *_dequeue_cmd(struct __queue *queue) 135{ 136 unsigned long irqL; 137 struct cmd_obj *obj; 138 139 spin_lock_irqsave(&(queue->lock), irqL); 140 if (list_empty(&(queue->queue))) 141 obj = NULL; 142 else { 143 obj = LIST_CONTAINOR(queue->queue.next, 144 struct cmd_obj, list); 145 list_del_init(&obj->list); 146 } 147 spin_unlock_irqrestore(&(queue->lock), irqL); 148 return obj; 149} 150 151u32 r8712_init_cmd_priv(struct cmd_priv *pcmdpriv) 152{ 153 return _init_cmd_priv(pcmdpriv); 154} 155 156u32 r8712_init_evt_priv(struct evt_priv *pevtpriv) 157{ 158 return _init_evt_priv(pevtpriv); 159} 160 161void r8712_free_evt_priv(struct evt_priv *pevtpriv) 162{ 163 _free_evt_priv(pevtpriv); 164} 165 166void r8712_free_cmd_priv(struct cmd_priv *pcmdpriv) 167{ 168 _free_cmd_priv(pcmdpriv); 169} 170 171u32 r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj) 172{ 173 int res; 174 175 if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag == true) 176 return _FAIL; 177 res = _enqueue_cmd(&pcmdpriv->cmd_queue, obj); 178 up(&pcmdpriv->cmd_queue_sema); 179 return res; 180} 181 182u32 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 == NULL) 188 return _SUCCESS; 189 if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag == true) 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 up(&pcmdpriv->cmd_queue_sema); 196 return _SUCCESS; 197} 198 199struct cmd_obj *r8712_dequeue_cmd(struct __queue *queue) 200{ 201 return _dequeue_cmd(queue); 202} 203 204void 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/* 217r8712_sitesurvey_cmd(~) 218 ### NOTE:#### (!!!!) 219 MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, 220 YOU SHOULD HAVE LOCKED pmlmepriv->lock 221*/ 222u8 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 == NULL) 232 return _FAIL; 233 psurveyPara = kmalloc(sizeof(*psurveyPara), GFP_ATOMIC); 234 if (psurveyPara == NULL) { 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 257u8 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 == NULL) 265 return _FAIL; 266 pbsetdataratepara = kmalloc(sizeof(*pbsetdataratepara), GFP_ATOMIC); 267 if (pbsetdataratepara == NULL) { 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 279u8 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 == NULL) 287 return _FAIL; 288 psetchplanpara = kmalloc(sizeof(*psetchplanpara), GFP_ATOMIC); 289 if (psetchplanpara == NULL) { 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 300u8 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 == NULL) 308 return _FAIL; 309 pssetbasicratepara = kmalloc(sizeof(*pssetbasicratepara), GFP_ATOMIC); 310 if (pssetbasicratepara == NULL) { 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/* power tracking mechanism setting */ 322u8 r8712_setptm_cmd(struct _adapter *padapter, u8 type) 323{ 324 struct cmd_obj *ph2c; 325 struct writePTM_parm *pwriteptmparm; 326 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 327 328 ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); 329 if (ph2c == NULL) 330 return _FAIL; 331 pwriteptmparm = kmalloc(sizeof(*pwriteptmparm), GFP_ATOMIC); 332 if (pwriteptmparm == NULL) { 333 kfree(ph2c); 334 return _FAIL; 335 } 336 init_h2fwcmd_w_parm_no_rsp(ph2c, pwriteptmparm, GEN_CMD_CODE(_SetPT)); 337 pwriteptmparm->type = type; 338 r8712_enqueue_cmd(pcmdpriv, ph2c); 339 return _SUCCESS; 340} 341 342u8 r8712_setfwdig_cmd(struct _adapter *padapter, u8 type) 343{ 344 struct cmd_obj *ph2c; 345 struct writePTM_parm *pwriteptmparm; 346 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 347 348 ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); 349 if (ph2c == NULL) 350 return _FAIL; 351 pwriteptmparm = kmalloc(sizeof(*pwriteptmparm), GFP_ATOMIC); 352 if (pwriteptmparm == NULL) { 353 kfree(ph2c); 354 return _FAIL; 355 } 356 init_h2fwcmd_w_parm_no_rsp(ph2c, pwriteptmparm, GEN_CMD_CODE(_SetDIG)); 357 pwriteptmparm->type = type; 358 r8712_enqueue_cmd(pcmdpriv, ph2c); 359 return _SUCCESS; 360} 361 362u8 r8712_setfwra_cmd(struct _adapter *padapter, u8 type) 363{ 364 struct cmd_obj *ph2c; 365 struct writePTM_parm *pwriteptmparm; 366 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 367 368 ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); 369 if (ph2c == NULL) 370 return _FAIL; 371 pwriteptmparm = kmalloc(sizeof(*pwriteptmparm), GFP_ATOMIC); 372 if (pwriteptmparm == NULL) { 373 kfree(ph2c); 374 return _FAIL; 375 } 376 init_h2fwcmd_w_parm_no_rsp(ph2c, pwriteptmparm, GEN_CMD_CODE(_SetRA)); 377 pwriteptmparm->type = type; 378 r8712_enqueue_cmd(pcmdpriv, ph2c); 379 return _SUCCESS; 380} 381 382u8 r8712_setrfreg_cmd(struct _adapter *padapter, u8 offset, u32 val) 383{ 384 struct cmd_obj *ph2c; 385 struct writeRF_parm *pwriterfparm; 386 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 387 388 ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); 389 if (ph2c == NULL) 390 return _FAIL; 391 pwriterfparm = kmalloc(sizeof(*pwriterfparm), GFP_ATOMIC); 392 if (pwriterfparm == NULL) { 393 kfree(ph2c); 394 return _FAIL; 395 } 396 init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg)); 397 pwriterfparm->offset = offset; 398 pwriterfparm->value = val; 399 r8712_enqueue_cmd(pcmdpriv, ph2c); 400 return _SUCCESS; 401} 402 403u8 r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval) 404{ 405 struct cmd_obj *ph2c; 406 struct readRF_parm *prdrfparm; 407 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 408 409 ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); 410 if (ph2c == NULL) 411 return _FAIL; 412 prdrfparm = kmalloc(sizeof(*prdrfparm), GFP_ATOMIC); 413 if (prdrfparm == NULL) { 414 kfree(ph2c); 415 return _FAIL; 416 } 417 INIT_LIST_HEAD(&ph2c->list); 418 ph2c->cmdcode = GEN_CMD_CODE(_GetRFReg); 419 ph2c->parmbuf = (unsigned char *)prdrfparm; 420 ph2c->cmdsz = sizeof(struct readRF_parm); 421 ph2c->rsp = pval; 422 ph2c->rspsz = sizeof(struct readRF_rsp); 423 prdrfparm->offset = offset; 424 r8712_enqueue_cmd(pcmdpriv, ph2c); 425 return _SUCCESS; 426} 427 428void r8712_getbbrfreg_cmdrsp_callback(struct _adapter *padapter, 429 struct cmd_obj *pcmd) 430{ 431 kfree(pcmd->parmbuf); 432 kfree(pcmd); 433 padapter->mppriv.workparam.bcompleted = true; 434} 435 436void r8712_readtssi_cmdrsp_callback(struct _adapter *padapter, 437 struct cmd_obj *pcmd) 438{ 439 kfree(pcmd->parmbuf); 440 kfree(pcmd); 441 442 padapter->mppriv.workparam.bcompleted = true; 443} 444 445u8 r8712_createbss_cmd(struct _adapter *padapter) 446{ 447 struct cmd_obj *pcmd; 448 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 449 struct wlan_bssid_ex *pdev_network = 450 &padapter->registrypriv.dev_network; 451 452 padapter->ledpriv.LedControlHandler(padapter, LED_CTL_START_TO_LINK); 453 pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC); 454 if (pcmd == NULL) 455 return _FAIL; 456 INIT_LIST_HEAD(&pcmd->list); 457 pcmd->cmdcode = _CreateBss_CMD_; 458 pcmd->parmbuf = (unsigned char *)pdev_network; 459 pcmd->cmdsz = r8712_get_ndis_wlan_bssid_ex_sz(( 460 struct ndis_wlan_bssid_ex *) 461 pdev_network); 462 pcmd->rsp = NULL; 463 pcmd->rspsz = 0; 464 /* notes: translate IELength & Length after assign to cmdsz; */ 465 pdev_network->Length = pcmd->cmdsz; 466 pdev_network->IELength = pdev_network->IELength; 467 pdev_network->Ssid.SsidLength = pdev_network->Ssid.SsidLength; 468 r8712_enqueue_cmd(pcmdpriv, pcmd); 469 return _SUCCESS; 470} 471 472u8 r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork) 473{ 474 uint t_len = 0; 475 struct ndis_wlan_bssid_ex *psecnetwork; 476 struct cmd_obj *pcmd; 477 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 478 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 479 struct qos_priv *pqospriv = &pmlmepriv->qospriv; 480 struct security_priv *psecuritypriv = &padapter->securitypriv; 481 struct registry_priv *pregistrypriv = &padapter->registrypriv; 482 enum NDIS_802_11_NETWORK_INFRASTRUCTURE ndis_network_mode = pnetwork-> 483 network.InfrastructureMode; 484 485 padapter->ledpriv.LedControlHandler(padapter, LED_CTL_START_TO_LINK); 486 pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC); 487 if (pcmd == NULL) 488 return _FAIL; 489 t_len = sizeof(u32) + 6 * sizeof(unsigned char) + 2 + 490 sizeof(struct ndis_802_11_ssid) + sizeof(u32) + 491 sizeof(s32) + 492 sizeof(enum NDIS_802_11_NETWORK_TYPE) + 493 sizeof(struct NDIS_802_11_CONFIGURATION) + 494 sizeof(enum NDIS_802_11_NETWORK_INFRASTRUCTURE) + 495 sizeof(NDIS_802_11_RATES_EX) + 496 sizeof(u32) + MAX_IE_SZ; 497 498 /* for hidden ap to set fw_state here */ 499 if (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) != 500 true) { 501 switch (ndis_network_mode) { 502 case Ndis802_11IBSS: 503 pmlmepriv->fw_state |= WIFI_ADHOC_STATE; 504 break; 505 case Ndis802_11Infrastructure: 506 pmlmepriv->fw_state |= WIFI_STATION_STATE; 507 break; 508 case Ndis802_11APMode: 509 case Ndis802_11AutoUnknown: 510 case Ndis802_11InfrastructureMax: 511 break; 512 } 513 } 514 psecnetwork = (struct ndis_wlan_bssid_ex *)&psecuritypriv->sec_bss; 515 if (psecnetwork == NULL) { 516 kfree(pcmd); 517 return _FAIL; 518 } 519 memcpy(psecnetwork, &pnetwork->network, t_len); 520 psecuritypriv->authenticator_ie[0] = (unsigned char) 521 psecnetwork->IELength; 522 if ((psecnetwork->IELength-12) < (256 - 1)) 523 memcpy(&psecuritypriv->authenticator_ie[1], 524 &psecnetwork->IEs[12], psecnetwork->IELength-12); 525 else 526 memcpy(&psecuritypriv->authenticator_ie[1], 527 &psecnetwork->IEs[12], (256-1)); 528 psecnetwork->IELength = 0; 529 /* If the driver wants to use the bssid to create the connection. 530 * If not, we copy the connecting AP's MAC address to it so that 531 * the driver just has the bssid information for PMKIDList searching. 532 */ 533 if (pmlmepriv->assoc_by_bssid == false) 534 ether_addr_copy(&pmlmepriv->assoc_bssid[0], 535 &pnetwork->network.MacAddress[0]); 536 psecnetwork->IELength = r8712_restruct_sec_ie(padapter, 537 &pnetwork->network.IEs[0], 538 &psecnetwork->IEs[0], 539 pnetwork->network.IELength); 540 pqospriv->qos_option = 0; 541 if (pregistrypriv->wmm_enable) { 542 u32 tmp_len; 543 544 tmp_len = r8712_restruct_wmm_ie(padapter, 545 &pnetwork->network.IEs[0], 546 &psecnetwork->IEs[0], 547 pnetwork->network.IELength, 548 psecnetwork->IELength); 549 if (psecnetwork->IELength != tmp_len) { 550 psecnetwork->IELength = tmp_len; 551 pqospriv->qos_option = 1; /* WMM IE in beacon */ 552 } else 553 pqospriv->qos_option = 0; /* no WMM IE in beacon */ 554 } 555 if (pregistrypriv->ht_enable) { 556 /* For WEP mode, we will use the bg mode to do the connection 557 * to avoid some IOT issues, especially for Realtek 8192u 558 * SoftAP. 559 */ 560 if ((padapter->securitypriv.PrivacyAlgrthm != _WEP40_) && 561 (padapter->securitypriv.PrivacyAlgrthm != _WEP104_)) { 562 /* restructure_ht_ie */ 563 r8712_restructure_ht_ie(padapter, 564 &pnetwork->network.IEs[0], 565 &psecnetwork->IEs[0], 566 pnetwork->network.IELength, 567 &psecnetwork->IELength); 568 } 569 } 570 psecuritypriv->supplicant_ie[0] = (u8)psecnetwork->IELength; 571 if (psecnetwork->IELength < 255) 572 memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0], 573 psecnetwork->IELength); 574 else 575 memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0], 576 255); 577 /* get cmdsz before endian conversion */ 578 pcmd->cmdsz = r8712_get_ndis_wlan_bssid_ex_sz(psecnetwork); 579#ifdef __BIG_ENDIAN 580 /* wlan_network endian conversion */ 581 psecnetwork->Length = cpu_to_le32(psecnetwork->Length); 582 psecnetwork->Ssid.SsidLength = cpu_to_le32( 583 psecnetwork->Ssid.SsidLength); 584 psecnetwork->Privacy = cpu_to_le32(psecnetwork->Privacy); 585 psecnetwork->Rssi = cpu_to_le32(psecnetwork->Rssi); 586 psecnetwork->NetworkTypeInUse = cpu_to_le32( 587 psecnetwork->NetworkTypeInUse); 588 psecnetwork->Configuration.ATIMWindow = cpu_to_le32( 589 psecnetwork->Configuration.ATIMWindow); 590 psecnetwork->Configuration.BeaconPeriod = cpu_to_le32( 591 psecnetwork->Configuration.BeaconPeriod); 592 psecnetwork->Configuration.DSConfig = cpu_to_le32( 593 psecnetwork->Configuration.DSConfig); 594 psecnetwork->Configuration.FHConfig.DwellTime = cpu_to_le32( 595 psecnetwork->Configuration.FHConfig.DwellTime); 596 psecnetwork->Configuration.FHConfig.HopPattern = cpu_to_le32( 597 psecnetwork->Configuration.FHConfig.HopPattern); 598 psecnetwork->Configuration.FHConfig.HopSet = cpu_to_le32( 599 psecnetwork->Configuration.FHConfig.HopSet); 600 psecnetwork->Configuration.FHConfig.Length = cpu_to_le32( 601 psecnetwork->Configuration.FHConfig.Length); 602 psecnetwork->Configuration.Length = cpu_to_le32( 603 psecnetwork->Configuration.Length); 604 psecnetwork->InfrastructureMode = cpu_to_le32( 605 psecnetwork->InfrastructureMode); 606 psecnetwork->IELength = cpu_to_le32(psecnetwork->IELength); 607#endif 608 INIT_LIST_HEAD(&pcmd->list); 609 pcmd->cmdcode = _JoinBss_CMD_; 610 pcmd->parmbuf = (unsigned char *)psecnetwork; 611 pcmd->rsp = NULL; 612 pcmd->rspsz = 0; 613 r8712_enqueue_cmd(pcmdpriv, pcmd); 614 return _SUCCESS; 615} 616 617u8 r8712_disassoc_cmd(struct _adapter *padapter) /* for sta_mode */ 618{ 619 struct cmd_obj *pdisconnect_cmd; 620 struct disconnect_parm *pdisconnect; 621 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 622 623 pdisconnect_cmd = kmalloc(sizeof(*pdisconnect_cmd), GFP_ATOMIC); 624 if (pdisconnect_cmd == NULL) 625 return _FAIL; 626 pdisconnect = kmalloc(sizeof(*pdisconnect), GFP_ATOMIC); 627 if (pdisconnect == NULL) { 628 kfree(pdisconnect_cmd); 629 return _FAIL; 630 } 631 init_h2fwcmd_w_parm_no_rsp(pdisconnect_cmd, pdisconnect, 632 _DisConnect_CMD_); 633 r8712_enqueue_cmd(pcmdpriv, pdisconnect_cmd); 634 return _SUCCESS; 635} 636 637u8 r8712_setopmode_cmd(struct _adapter *padapter, 638 enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype) 639{ 640 struct cmd_obj *ph2c; 641 struct setopmode_parm *psetop; 642 643 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 644 645 ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); 646 if (ph2c == NULL) 647 return _FAIL; 648 psetop = kmalloc(sizeof(*psetop), GFP_ATOMIC); 649 if (psetop == NULL) { 650 kfree(ph2c); 651 return _FAIL; 652 } 653 init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_); 654 psetop->mode = (u8)networktype; 655 r8712_enqueue_cmd(pcmdpriv, ph2c); 656 return _SUCCESS; 657} 658 659u8 r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key) 660{ 661 struct cmd_obj *ph2c; 662 struct set_stakey_parm *psetstakey_para; 663 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 664 struct set_stakey_rsp *psetstakey_rsp = NULL; 665 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 666 struct security_priv *psecuritypriv = &padapter->securitypriv; 667 struct sta_info *sta = (struct sta_info *)psta; 668 669 ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); 670 if (ph2c == NULL) 671 return _FAIL; 672 psetstakey_para = kmalloc(sizeof(*psetstakey_para), GFP_ATOMIC); 673 if (psetstakey_para == NULL) { 674 kfree(ph2c); 675 return _FAIL; 676 } 677 psetstakey_rsp = kmalloc(sizeof(*psetstakey_rsp), GFP_ATOMIC); 678 if (psetstakey_rsp == NULL) { 679 kfree(ph2c); 680 kfree(psetstakey_para); 681 return _FAIL; 682 } 683 init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); 684 ph2c->rsp = (u8 *) psetstakey_rsp; 685 ph2c->rspsz = sizeof(struct set_stakey_rsp); 686 ether_addr_copy(psetstakey_para->addr, sta->hwaddr); 687 if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) 688 psetstakey_para->algorithm = (unsigned char) 689 psecuritypriv->PrivacyAlgrthm; 690 else 691 GET_ENCRY_ALGO(psecuritypriv, sta, 692 psetstakey_para->algorithm, false); 693 if (unicast_key == true) 694 memcpy(&psetstakey_para->key, &sta->x_UncstKey, 16); 695 else 696 memcpy(&psetstakey_para->key, 697 &psecuritypriv->XGrpKey[ 698 psecuritypriv->XGrpKeyid - 1]. skey, 16); 699 r8712_enqueue_cmd(pcmdpriv, ph2c); 700 return _SUCCESS; 701} 702 703u8 r8712_setrfintfs_cmd(struct _adapter *padapter, u8 mode) 704{ 705 struct cmd_obj *ph2c; 706 struct setrfintfs_parm *psetrfintfsparm; 707 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 708 709 ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); 710 if (ph2c == NULL) 711 return _FAIL; 712 psetrfintfsparm = kmalloc(sizeof(*psetrfintfsparm), GFP_ATOMIC); 713 if (psetrfintfsparm == NULL) { 714 kfree(ph2c); 715 return _FAIL; 716 } 717 init_h2fwcmd_w_parm_no_rsp(ph2c, psetrfintfsparm, 718 GEN_CMD_CODE(_SetRFIntFs)); 719 psetrfintfsparm->rfintfs = mode; 720 r8712_enqueue_cmd(pcmdpriv, ph2c); 721 return _SUCCESS; 722} 723 724u8 r8712_setrttbl_cmd(struct _adapter *padapter, 725 struct setratable_parm *prate_table) 726{ 727 struct cmd_obj *ph2c; 728 struct setratable_parm *psetrttblparm; 729 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 730 731 ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); 732 if (ph2c == NULL) 733 return _FAIL; 734 psetrttblparm = kmalloc(sizeof(*psetrttblparm), GFP_ATOMIC); 735 if (psetrttblparm == NULL) { 736 kfree(ph2c); 737 return _FAIL; 738 } 739 init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, 740 GEN_CMD_CODE(_SetRaTable)); 741 memcpy(psetrttblparm, prate_table, sizeof(struct setratable_parm)); 742 r8712_enqueue_cmd(pcmdpriv, ph2c); 743 return _SUCCESS; 744} 745 746u8 r8712_gettssi_cmd(struct _adapter *padapter, u8 offset, u8 *pval) 747{ 748 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 749 struct cmd_obj *ph2c; 750 struct readTSSI_parm *prdtssiparm; 751 752 ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); 753 if (ph2c == NULL) 754 return _FAIL; 755 prdtssiparm = kmalloc(sizeof(*prdtssiparm), GFP_ATOMIC); 756 if (prdtssiparm == NULL) { 757 kfree(ph2c); 758 return _FAIL; 759 } 760 INIT_LIST_HEAD(&ph2c->list); 761 ph2c->cmdcode = GEN_CMD_CODE(_ReadTSSI); 762 ph2c->parmbuf = (unsigned char *)prdtssiparm; 763 ph2c->cmdsz = sizeof(struct readTSSI_parm); 764 ph2c->rsp = pval; 765 ph2c->rspsz = sizeof(struct readTSSI_rsp); 766 767 prdtssiparm->offset = offset; 768 r8712_enqueue_cmd(pcmdpriv, ph2c); 769 return _SUCCESS; 770} 771 772u8 r8712_setMacAddr_cmd(struct _adapter *padapter, u8 *mac_addr) 773{ 774 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 775 struct cmd_obj *ph2c; 776 struct SetMacAddr_param *psetMacAddr_para; 777 778 ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); 779 if (ph2c == NULL) 780 return _FAIL; 781 psetMacAddr_para = kmalloc(sizeof(*psetMacAddr_para), GFP_ATOMIC); 782 if (psetMacAddr_para == NULL) { 783 kfree(ph2c); 784 return _FAIL; 785 } 786 init_h2fwcmd_w_parm_no_rsp(ph2c, psetMacAddr_para, 787 _SetMacAddress_CMD_); 788 ether_addr_copy(psetMacAddr_para->MacAddr, mac_addr); 789 r8712_enqueue_cmd(pcmdpriv, ph2c); 790 return _SUCCESS; 791} 792 793u8 r8712_setassocsta_cmd(struct _adapter *padapter, u8 *mac_addr) 794{ 795 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 796 struct cmd_obj *ph2c; 797 struct set_assocsta_parm *psetassocsta_para; 798 struct set_assocsta_rsp *psetassocsta_rsp = NULL; 799 800 ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); 801 if (ph2c == NULL) 802 return _FAIL; 803 psetassocsta_para = kmalloc(sizeof(*psetassocsta_para), GFP_ATOMIC); 804 if (psetassocsta_para == NULL) { 805 kfree(ph2c); 806 return _FAIL; 807 } 808 psetassocsta_rsp = kmalloc(sizeof(*psetassocsta_rsp), GFP_ATOMIC); 809 if (psetassocsta_rsp == NULL) { 810 kfree(ph2c); 811 kfree(psetassocsta_para); 812 return _FAIL; 813 } 814 init_h2fwcmd_w_parm_no_rsp(ph2c, psetassocsta_para, _SetAssocSta_CMD_); 815 ph2c->rsp = (u8 *) psetassocsta_rsp; 816 ph2c->rspsz = sizeof(struct set_assocsta_rsp); 817 ether_addr_copy(psetassocsta_para->addr, mac_addr); 818 r8712_enqueue_cmd(pcmdpriv, ph2c); 819 return _SUCCESS; 820} 821 822u8 r8712_addbareq_cmd(struct _adapter *padapter, u8 tid) 823{ 824 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 825 struct cmd_obj *ph2c; 826 struct addBaReq_parm *paddbareq_parm; 827 828 ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); 829 if (ph2c == NULL) 830 return _FAIL; 831 paddbareq_parm = kmalloc(sizeof(*paddbareq_parm), GFP_ATOMIC); 832 if (paddbareq_parm == NULL) { 833 kfree(ph2c); 834 return _FAIL; 835 } 836 paddbareq_parm->tid = tid; 837 init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, 838 GEN_CMD_CODE(_AddBAReq)); 839 r8712_enqueue_cmd_ex(pcmdpriv, ph2c); 840 return _SUCCESS; 841} 842 843u8 r8712_wdg_wk_cmd(struct _adapter *padapter) 844{ 845 struct cmd_obj *ph2c; 846 struct drvint_cmd_parm *pdrvintcmd_param; 847 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 848 849 ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); 850 if (ph2c == NULL) 851 return _FAIL; 852 pdrvintcmd_param = kmalloc(sizeof(*pdrvintcmd_param), GFP_ATOMIC); 853 if (pdrvintcmd_param == NULL) { 854 kfree(ph2c); 855 return _FAIL; 856 } 857 pdrvintcmd_param->i_cid = WDG_WK_CID; 858 pdrvintcmd_param->sz = 0; 859 pdrvintcmd_param->pbuf = NULL; 860 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvintcmd_param, _DRV_INT_CMD_); 861 r8712_enqueue_cmd_ex(pcmdpriv, ph2c); 862 return _SUCCESS; 863} 864 865void r8712_survey_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd) 866{ 867 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 868 869 if (pcmd->res != H2C_SUCCESS) 870 clr_fwstate(pmlmepriv, _FW_UNDER_SURVEY); 871 r8712_free_cmd_obj(pcmd); 872} 873 874void r8712_disassoc_cmd_callback(struct _adapter *padapter, 875 struct cmd_obj *pcmd) 876{ 877 unsigned long irqL; 878 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 879 880 if (pcmd->res != H2C_SUCCESS) { 881 spin_lock_irqsave(&pmlmepriv->lock, irqL); 882 set_fwstate(pmlmepriv, _FW_LINKED); 883 spin_unlock_irqrestore(&pmlmepriv->lock, irqL); 884 return; 885 } 886 r8712_free_cmd_obj(pcmd); 887} 888 889void r8712_joinbss_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd) 890{ 891 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 892 893 if (pcmd->res != H2C_SUCCESS) 894 mod_timer(&pmlmepriv->assoc_timer, 895 jiffies + msecs_to_jiffies(1)); 896 r8712_free_cmd_obj(pcmd); 897} 898 899void r8712_createbss_cmd_callback(struct _adapter *padapter, 900 struct cmd_obj *pcmd) 901{ 902 unsigned long irqL; 903 struct sta_info *psta = NULL; 904 struct wlan_network *pwlan = NULL; 905 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 906 struct ndis_wlan_bssid_ex *pnetwork = (struct ndis_wlan_bssid_ex *) 907 pcmd->parmbuf; 908 struct wlan_network *tgt_network = &(pmlmepriv->cur_network); 909 910 if (pcmd->res != H2C_SUCCESS) 911 mod_timer(&pmlmepriv->assoc_timer, 912 jiffies + msecs_to_jiffies(1)); 913 del_timer(&pmlmepriv->assoc_timer); 914#ifdef __BIG_ENDIAN 915 /* endian_convert */ 916 pnetwork->Length = le32_to_cpu(pnetwork->Length); 917 pnetwork->Ssid.SsidLength = le32_to_cpu(pnetwork->Ssid.SsidLength); 918 pnetwork->Privacy = le32_to_cpu(pnetwork->Privacy); 919 pnetwork->Rssi = le32_to_cpu(pnetwork->Rssi); 920 pnetwork->NetworkTypeInUse = le32_to_cpu(pnetwork->NetworkTypeInUse); 921 pnetwork->Configuration.ATIMWindow = le32_to_cpu(pnetwork-> 922 Configuration.ATIMWindow); 923 pnetwork->Configuration.DSConfig = le32_to_cpu(pnetwork-> 924 Configuration.DSConfig); 925 pnetwork->Configuration.FHConfig.DwellTime = le32_to_cpu(pnetwork-> 926 Configuration.FHConfig.DwellTime); 927 pnetwork->Configuration.FHConfig.HopPattern = le32_to_cpu(pnetwork-> 928 Configuration.FHConfig.HopPattern); 929 pnetwork->Configuration.FHConfig.HopSet = le32_to_cpu(pnetwork-> 930 Configuration.FHConfig.HopSet); 931 pnetwork->Configuration.FHConfig.Length = le32_to_cpu(pnetwork-> 932 Configuration.FHConfig.Length); 933 pnetwork->Configuration.Length = le32_to_cpu(pnetwork-> 934 Configuration.Length); 935 pnetwork->InfrastructureMode = le32_to_cpu(pnetwork-> 936 InfrastructureMode); 937 pnetwork->IELength = le32_to_cpu(pnetwork->IELength); 938#endif 939 spin_lock_irqsave(&pmlmepriv->lock, irqL); 940 if ((pmlmepriv->fw_state) & WIFI_AP_STATE) { 941 psta = r8712_get_stainfo(&padapter->stapriv, 942 pnetwork->MacAddress); 943 if (!psta) { 944 psta = r8712_alloc_stainfo(&padapter->stapriv, 945 pnetwork->MacAddress); 946 if (psta == NULL) 947 goto createbss_cmd_fail; 948 } 949 r8712_indicate_connect(padapter); 950 } else { 951 pwlan = _r8712_alloc_network(pmlmepriv); 952 if (pwlan == NULL) { 953 pwlan = r8712_get_oldest_wlan_network( 954 &pmlmepriv->scanned_queue); 955 if (pwlan == NULL) 956 goto createbss_cmd_fail; 957 pwlan->last_scanned = jiffies; 958 } else 959 list_add_tail(&(pwlan->list), 960 &pmlmepriv->scanned_queue.queue); 961 pnetwork->Length = r8712_get_ndis_wlan_bssid_ex_sz(pnetwork); 962 memcpy(&(pwlan->network), pnetwork, pnetwork->Length); 963 pwlan->fixed = true; 964 memcpy(&tgt_network->network, pnetwork, 965 (r8712_get_ndis_wlan_bssid_ex_sz(pnetwork))); 966 if (pmlmepriv->fw_state & _FW_UNDER_LINKING) 967 pmlmepriv->fw_state ^= _FW_UNDER_LINKING; 968 /* we will set _FW_LINKED when there is one more sat to 969 * join us (stassoc_event_callback) */ 970 } 971createbss_cmd_fail: 972 spin_unlock_irqrestore(&pmlmepriv->lock, irqL); 973 r8712_free_cmd_obj(pcmd); 974} 975 976void r8712_setstaKey_cmdrsp_callback(struct _adapter *padapter, 977 struct cmd_obj *pcmd) 978{ 979 struct sta_priv *pstapriv = &padapter->stapriv; 980 struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *) 981 (pcmd->rsp); 982 struct sta_info *psta = r8712_get_stainfo(pstapriv, 983 psetstakey_rsp->addr); 984 985 if (psta == NULL) 986 goto exit; 987 psta->aid = psta->mac_id = psetstakey_rsp->keyid; /*CAM_ID(CAM_ENTRY)*/ 988exit: 989 r8712_free_cmd_obj(pcmd); 990} 991 992void r8712_setassocsta_cmdrsp_callback(struct _adapter *padapter, 993 struct cmd_obj *pcmd) 994{ 995 unsigned long irqL; 996 struct sta_priv *pstapriv = &padapter->stapriv; 997 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 998 struct set_assocsta_parm *passocsta_parm = 999 (struct set_assocsta_parm *)(pcmd->parmbuf); 1000 struct set_assocsta_rsp *passocsta_rsp = 1001 (struct set_assocsta_rsp *) (pcmd->rsp); 1002 struct sta_info *psta = r8712_get_stainfo(pstapriv, 1003 passocsta_parm->addr); 1004 1005 if (psta == NULL) 1006 return; 1007 psta->aid = psta->mac_id = passocsta_rsp->cam_id; 1008 spin_lock_irqsave(&pmlmepriv->lock, irqL); 1009 if ((check_fwstate(pmlmepriv, WIFI_MP_STATE)) && 1010 (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))) 1011 pmlmepriv->fw_state ^= _FW_UNDER_LINKING; 1012 set_fwstate(pmlmepriv, _FW_LINKED); 1013 spin_unlock_irqrestore(&pmlmepriv->lock, irqL); 1014 r8712_free_cmd_obj(pcmd); 1015} 1016 1017u8 r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl, 1018 u32 tryPktCnt, u32 tryPktInterval, u32 firstStageTO) 1019{ 1020 struct cmd_obj *ph2c; 1021 struct DisconnectCtrlEx_param *param; 1022 struct cmd_priv *pcmdpriv = &adapter->cmdpriv; 1023 1024 ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); 1025 if (ph2c == NULL) 1026 return _FAIL; 1027 param = kzalloc(sizeof(*param), GFP_ATOMIC); 1028 if (param == NULL) { 1029 kfree(ph2c); 1030 return _FAIL; 1031 } 1032 1033 param->EnableDrvCtrl = (unsigned char)enableDrvCtrl; 1034 param->TryPktCnt = (unsigned char)tryPktCnt; 1035 param->TryPktInterval = (unsigned char)tryPktInterval; 1036 param->FirstStageTO = (unsigned int)firstStageTO; 1037 1038 init_h2fwcmd_w_parm_no_rsp(ph2c, param, 1039 GEN_CMD_CODE(_DisconnectCtrlEx)); 1040 r8712_enqueue_cmd(pcmdpriv, ph2c); 1041 return _SUCCESS; 1042} 1043