linux/drivers/staging/rtl8712/rtl871x_cmd.c
<<
>>
Prefs
   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
  58static 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
  88static 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
 102static void _free_evt_priv(struct evt_priv *pevtpriv)
 103{
 104        kfree(pevtpriv->evt_allocated_buf);
 105}
 106
 107static 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
 125static 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
 137static 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
 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)
 176                return _FAIL;
 177        res = _enqueue_cmd(&pcmdpriv->cmd_queue, obj);
 178        complete(&pcmdpriv->cmd_queue_comp);
 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)
 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
 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/*
 217 *      r8712_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)
 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
 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)
 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
 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)
 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
 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)
 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
 321u8 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
 341u8 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
 361u8 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
 382u8 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
 407void 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
 415void 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
 424u8 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
 449u8 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
 588u8 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
 608u8 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
 630u8 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
 674u8 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
 695u8 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
 717u8 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
 738u8 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
 767u8 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
 788u8 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
 810void 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
 819void 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
 834void 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
 844void 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        }
 918createbss_cmd_fail:
 919        spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
 920        r8712_free_cmd_obj(pcmd);
 921}
 922
 923void 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)*/
 935exit:
 936        r8712_free_cmd_obj(pcmd);
 937}
 938
 939void 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
 964u8 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