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