Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /******************************************************************************
0003  * rtl871x_cmd.c
0004  *
0005  * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
0006  * Linux device driver for RTL8192SU
0007  *
0008  * Modifications for inclusion into the Linux staging tree are
0009  * Copyright(c) 2010 Larry Finger. All rights reserved.
0010  *
0011  * Contact information:
0012  * WLAN FAE <wlanfae@realtek.com>
0013  * Larry Finger <Larry.Finger@lwfinger.net>
0014  *
0015  ******************************************************************************/
0016 
0017 #define _RTL871X_CMD_C_
0018 
0019 #include <linux/compiler.h>
0020 #include <linux/kernel.h>
0021 #include <linux/errno.h>
0022 #include <linux/slab.h>
0023 #include <linux/module.h>
0024 #include <linux/kref.h>
0025 #include <linux/netdevice.h>
0026 #include <linux/skbuff.h>
0027 #include <linux/usb.h>
0028 #include <linux/usb/ch9.h>
0029 #include <linux/circ_buf.h>
0030 #include <linux/uaccess.h>
0031 #include <asm/byteorder.h>
0032 #include <linux/atomic.h>
0033 #include <linux/semaphore.h>
0034 #include <linux/rtnetlink.h>
0035 
0036 #include "osdep_service.h"
0037 #include "drv_types.h"
0038 #include "recv_osdep.h"
0039 #include "mlme_osdep.h"
0040 
0041 /*
0042  * Caller and the r8712_cmd_thread can protect cmd_q by spin_lock.
0043  * No irqsave is necessary.
0044  */
0045 
0046 int r8712_init_cmd_priv(struct cmd_priv *pcmdpriv)
0047 {
0048     init_completion(&pcmdpriv->cmd_queue_comp);
0049     init_completion(&pcmdpriv->terminate_cmdthread_comp);
0050 
0051     _init_queue(&(pcmdpriv->cmd_queue));
0052 
0053     /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
0054     pcmdpriv->cmd_seq = 1;
0055     pcmdpriv->cmd_allocated_buf = kmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ,
0056                           GFP_ATOMIC);
0057     if (!pcmdpriv->cmd_allocated_buf)
0058         return -ENOMEM;
0059     pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf  +  CMDBUFF_ALIGN_SZ -
0060                 ((addr_t)(pcmdpriv->cmd_allocated_buf) &
0061                 (CMDBUFF_ALIGN_SZ - 1));
0062     pcmdpriv->rsp_allocated_buf = kmalloc(MAX_RSPSZ + 4, GFP_ATOMIC);
0063     if (!pcmdpriv->rsp_allocated_buf) {
0064         kfree(pcmdpriv->cmd_allocated_buf);
0065         pcmdpriv->cmd_allocated_buf = NULL;
0066         return -ENOMEM;
0067     }
0068     pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf  +  4 -
0069                 ((addr_t)(pcmdpriv->rsp_allocated_buf) & 3);
0070     pcmdpriv->cmd_issued_cnt = 0;
0071     pcmdpriv->cmd_done_cnt = 0;
0072     pcmdpriv->rsp_cnt = 0;
0073     return 0;
0074 }
0075 
0076 int r8712_init_evt_priv(struct evt_priv *pevtpriv)
0077 {
0078     /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
0079     pevtpriv->event_seq = 0;
0080     pevtpriv->evt_allocated_buf = kmalloc(MAX_EVTSZ + 4, GFP_ATOMIC);
0081 
0082     if (!pevtpriv->evt_allocated_buf)
0083         return -ENOMEM;
0084     pevtpriv->evt_buf = pevtpriv->evt_allocated_buf  +  4 -
0085                 ((addr_t)(pevtpriv->evt_allocated_buf) & 3);
0086     pevtpriv->evt_done_cnt = 0;
0087     return 0;
0088 }
0089 
0090 void r8712_free_evt_priv(struct evt_priv *pevtpriv)
0091 {
0092     kfree(pevtpriv->evt_allocated_buf);
0093 }
0094 
0095 void r8712_free_cmd_priv(struct cmd_priv *pcmdpriv)
0096 {
0097     if (pcmdpriv) {
0098         kfree(pcmdpriv->cmd_allocated_buf);
0099         kfree(pcmdpriv->rsp_allocated_buf);
0100     }
0101 }
0102 
0103 /*
0104  * Calling Context:
0105  *
0106  * r8712_enqueue_cmd can only be called between kernel thread,
0107  * since only spin_lock is used.
0108  *
0109  * ISR/Call-Back functions can't call this sub-function.
0110  *
0111  */
0112 
0113 void r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj)
0114 {
0115     struct __queue *queue;
0116     unsigned long irqL;
0117 
0118     if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag)
0119         return;
0120     if (!obj)
0121         return;
0122     queue = &pcmdpriv->cmd_queue;
0123     spin_lock_irqsave(&queue->lock, irqL);
0124     list_add_tail(&obj->list, &queue->queue);
0125     spin_unlock_irqrestore(&queue->lock, irqL);
0126     complete(&pcmdpriv->cmd_queue_comp);
0127 }
0128 
0129 struct cmd_obj *r8712_dequeue_cmd(struct  __queue *queue)
0130 {
0131     unsigned long irqL;
0132     struct cmd_obj *obj;
0133 
0134     spin_lock_irqsave(&queue->lock, irqL);
0135     obj = list_first_entry_or_null(&queue->queue,
0136                        struct cmd_obj, list);
0137     if (obj)
0138         list_del_init(&obj->list);
0139     spin_unlock_irqrestore(&queue->lock, irqL);
0140     return obj;
0141 }
0142 
0143 void r8712_enqueue_cmd_ex(struct cmd_priv *pcmdpriv, struct cmd_obj *obj)
0144 {
0145     unsigned long irqL;
0146     struct  __queue *queue;
0147 
0148     if (!obj)
0149         return;
0150     if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag)
0151         return;
0152     queue = &pcmdpriv->cmd_queue;
0153     spin_lock_irqsave(&queue->lock, irqL);
0154     list_add_tail(&obj->list, &queue->queue);
0155     spin_unlock_irqrestore(&queue->lock, irqL);
0156     complete(&pcmdpriv->cmd_queue_comp);
0157 }
0158 
0159 void r8712_free_cmd_obj(struct cmd_obj *pcmd)
0160 {
0161     if ((pcmd->cmdcode != _JoinBss_CMD_) &&
0162         (pcmd->cmdcode != _CreateBss_CMD_))
0163         kfree(pcmd->parmbuf);
0164     if (pcmd->rsp) {
0165         if (pcmd->rspsz != 0)
0166             kfree(pcmd->rsp);
0167     }
0168     kfree(pcmd);
0169 }
0170 
0171 u8 r8712_sitesurvey_cmd(struct _adapter *padapter,
0172             struct ndis_802_11_ssid *pssid)
0173     __must_hold(&padapter->mlmepriv.lock)
0174 {
0175     struct cmd_obj  *ph2c;
0176     struct sitesurvey_parm  *psurveyPara;
0177     struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
0178     struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
0179 
0180     ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
0181     if (!ph2c)
0182         return _FAIL;
0183     psurveyPara = kmalloc(sizeof(*psurveyPara), GFP_ATOMIC);
0184     if (!psurveyPara) {
0185         kfree(ph2c);
0186         return _FAIL;
0187     }
0188     init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara,
0189                    GEN_CMD_CODE(_SiteSurvey));
0190     psurveyPara->bsslimit = cpu_to_le32(48);
0191     psurveyPara->passive_mode = cpu_to_le32(pmlmepriv->passive_mode);
0192     psurveyPara->ss_ssidlen = 0;
0193     memset(psurveyPara->ss_ssid, 0, IW_ESSID_MAX_SIZE + 1);
0194     if (pssid && pssid->SsidLength) {
0195         int len = min_t(int, pssid->SsidLength, IW_ESSID_MAX_SIZE);
0196 
0197         memcpy(psurveyPara->ss_ssid, pssid->Ssid, len);
0198         psurveyPara->ss_ssidlen = cpu_to_le32(len);
0199     }
0200     set_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
0201     r8712_enqueue_cmd(pcmdpriv, ph2c);
0202     mod_timer(&pmlmepriv->scan_to_timer,
0203           jiffies + msecs_to_jiffies(SCANNING_TIMEOUT));
0204     padapter->ledpriv.LedControlHandler(padapter, LED_CTL_SITE_SURVEY);
0205     complete(&padapter->rx_filter_ready);
0206     return _SUCCESS;
0207 }
0208 
0209 int r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset)
0210 {
0211     struct cmd_obj      *ph2c;
0212     struct setdatarate_parm *pbsetdataratepara;
0213     struct cmd_priv     *pcmdpriv = &padapter->cmdpriv;
0214 
0215     ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
0216     if (!ph2c)
0217         return -ENOMEM;
0218     pbsetdataratepara = kmalloc(sizeof(*pbsetdataratepara), GFP_ATOMIC);
0219     if (!pbsetdataratepara) {
0220         kfree(ph2c);
0221         return -ENOMEM;
0222     }
0223     init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara,
0224                    GEN_CMD_CODE(_SetDataRate));
0225     pbsetdataratepara->mac_id = 5;
0226     memcpy(pbsetdataratepara->datarates, rateset, NumRates);
0227     r8712_enqueue_cmd(pcmdpriv, ph2c);
0228     return 0;
0229 }
0230 
0231 void r8712_set_chplan_cmd(struct _adapter *padapter, int chplan)
0232 {
0233     struct cmd_obj *ph2c;
0234     struct SetChannelPlan_param *psetchplanpara;
0235     struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
0236 
0237     ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
0238     if (!ph2c)
0239         return;
0240     psetchplanpara = kmalloc(sizeof(*psetchplanpara), GFP_ATOMIC);
0241     if (!psetchplanpara) {
0242         kfree(ph2c);
0243         return;
0244     }
0245     init_h2fwcmd_w_parm_no_rsp(ph2c, psetchplanpara,
0246                 GEN_CMD_CODE(_SetChannelPlan));
0247     psetchplanpara->ChannelPlan = chplan;
0248     r8712_enqueue_cmd(pcmdpriv, ph2c);
0249 }
0250 
0251 int r8712_setrfreg_cmd(struct _adapter  *padapter, u8 offset, u32 val)
0252 {
0253     struct cmd_obj *ph2c;
0254     struct writeRF_parm *pwriterfparm;
0255     struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
0256 
0257     ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
0258     if (!ph2c)
0259         return -ENOMEM;
0260     pwriterfparm = kmalloc(sizeof(*pwriterfparm), GFP_ATOMIC);
0261     if (!pwriterfparm) {
0262         kfree(ph2c);
0263         return -ENOMEM;
0264     }
0265     init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg));
0266     pwriterfparm->offset = offset;
0267     pwriterfparm->value = val;
0268     r8712_enqueue_cmd(pcmdpriv, ph2c);
0269     return 0;
0270 }
0271 
0272 int r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval)
0273 {
0274     struct cmd_obj *ph2c;
0275     struct readRF_parm *prdrfparm;
0276     struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
0277 
0278     ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
0279     if (!ph2c)
0280         return -ENOMEM;
0281     prdrfparm = kmalloc(sizeof(*prdrfparm), GFP_ATOMIC);
0282     if (!prdrfparm) {
0283         kfree(ph2c);
0284         return -ENOMEM;
0285     }
0286     INIT_LIST_HEAD(&ph2c->list);
0287     ph2c->cmdcode = GEN_CMD_CODE(_GetRFReg);
0288     ph2c->parmbuf = (unsigned char *)prdrfparm;
0289     ph2c->cmdsz =  sizeof(struct readRF_parm);
0290     ph2c->rsp = pval;
0291     ph2c->rspsz = sizeof(struct readRF_rsp);
0292     prdrfparm->offset = offset;
0293     r8712_enqueue_cmd(pcmdpriv, ph2c);
0294     return 0;
0295 }
0296 
0297 void r8712_getbbrfreg_cmdrsp_callback(struct _adapter *padapter,
0298                       struct cmd_obj *pcmd)
0299 {
0300     kfree(pcmd->parmbuf);
0301     kfree(pcmd);
0302     padapter->mppriv.workparam.bcompleted = true;
0303 }
0304 
0305 void r8712_readtssi_cmdrsp_callback(struct _adapter *padapter,
0306                 struct cmd_obj *pcmd)
0307 {
0308     kfree(pcmd->parmbuf);
0309     kfree(pcmd);
0310 
0311     padapter->mppriv.workparam.bcompleted = true;
0312 }
0313 
0314 int r8712_createbss_cmd(struct _adapter *padapter)
0315 {
0316     struct cmd_obj *pcmd;
0317     struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
0318     struct wlan_bssid_ex *pdev_network =
0319                  &padapter->registrypriv.dev_network;
0320 
0321     padapter->ledpriv.LedControlHandler(padapter, LED_CTL_START_TO_LINK);
0322     pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC);
0323     if (!pcmd)
0324         return -ENOMEM;
0325     INIT_LIST_HEAD(&pcmd->list);
0326     pcmd->cmdcode = _CreateBss_CMD_;
0327     pcmd->parmbuf = (unsigned char *)pdev_network;
0328     pcmd->cmdsz = r8712_get_wlan_bssid_ex_sz(pdev_network);
0329     pcmd->rsp = NULL;
0330     pcmd->rspsz = 0;
0331     /* notes: translate IELength & Length after assign to cmdsz; */
0332     pdev_network->Length = pcmd->cmdsz;
0333     pdev_network->IELength = pdev_network->IELength;
0334     pdev_network->Ssid.SsidLength = pdev_network->Ssid.SsidLength;
0335     r8712_enqueue_cmd(pcmdpriv, pcmd);
0336     return 0;
0337 }
0338 
0339 int r8712_joinbss_cmd(struct _adapter  *padapter, struct wlan_network *pnetwork)
0340 {
0341     struct wlan_bssid_ex *psecnetwork;
0342     struct cmd_obj      *pcmd;
0343     struct cmd_priv     *pcmdpriv = &padapter->cmdpriv;
0344     struct mlme_priv    *pmlmepriv = &padapter->mlmepriv;
0345     struct qos_priv     *pqospriv = &pmlmepriv->qospriv;
0346     struct security_priv    *psecuritypriv = &padapter->securitypriv;
0347     struct registry_priv    *pregistrypriv = &padapter->registrypriv;
0348     enum NDIS_802_11_NETWORK_INFRASTRUCTURE ndis_network_mode =
0349         pnetwork->network.InfrastructureMode;
0350 
0351     padapter->ledpriv.LedControlHandler(padapter, LED_CTL_START_TO_LINK);
0352     pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC);
0353     if (!pcmd)
0354         return -ENOMEM;
0355 
0356     /* for hidden ap to set fw_state here */
0357     if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) !=
0358         true) {
0359         switch (ndis_network_mode) {
0360         case Ndis802_11IBSS:
0361             pmlmepriv->fw_state |= WIFI_ADHOC_STATE;
0362             break;
0363         case Ndis802_11Infrastructure:
0364             pmlmepriv->fw_state |= WIFI_STATION_STATE;
0365             break;
0366         case Ndis802_11APMode:
0367         case Ndis802_11AutoUnknown:
0368         case Ndis802_11InfrastructureMax:
0369             break;
0370         }
0371     }
0372     psecnetwork = &psecuritypriv->sec_bss;
0373     memcpy(psecnetwork, &pnetwork->network, sizeof(*psecnetwork));
0374     psecuritypriv->authenticator_ie[0] = (unsigned char)
0375                          psecnetwork->IELength;
0376     if ((psecnetwork->IELength - 12) < (256 - 1))
0377         memcpy(&psecuritypriv->authenticator_ie[1],
0378             &psecnetwork->IEs[12], psecnetwork->IELength - 12);
0379     else
0380         memcpy(&psecuritypriv->authenticator_ie[1],
0381             &psecnetwork->IEs[12], (256 - 1));
0382     psecnetwork->IELength = 0;
0383     /*
0384      * If the driver wants to use the bssid to create the connection.
0385      * If not, we copy the connecting AP's MAC address to it so that
0386      * the driver just has the bssid information for PMKIDList searching.
0387      */
0388     if (!pmlmepriv->assoc_by_bssid)
0389         ether_addr_copy(&pmlmepriv->assoc_bssid[0],
0390                 &pnetwork->network.MacAddress[0]);
0391     psecnetwork->IELength = r8712_restruct_sec_ie(padapter,
0392                         &pnetwork->network.IEs[0],
0393                         &psecnetwork->IEs[0],
0394                         pnetwork->network.IELength);
0395     pqospriv->qos_option = 0;
0396     if (pregistrypriv->wmm_enable) {
0397         u32 tmp_len;
0398 
0399         tmp_len = r8712_restruct_wmm_ie(padapter,
0400                       &pnetwork->network.IEs[0],
0401                       &psecnetwork->IEs[0],
0402                       pnetwork->network.IELength,
0403                       psecnetwork->IELength);
0404         if (psecnetwork->IELength != tmp_len) {
0405             psecnetwork->IELength = tmp_len;
0406             pqospriv->qos_option = 1; /* WMM IE in beacon */
0407         } else {
0408             pqospriv->qos_option = 0; /* no WMM IE in beacon */
0409         }
0410     }
0411     if (pregistrypriv->ht_enable) {
0412         /*
0413          * For WEP mode, we will use the bg mode to do the connection
0414          * to avoid some IOT issues, especially for Realtek 8192u
0415          * SoftAP.
0416          */
0417         if ((padapter->securitypriv.PrivacyAlgrthm != _WEP40_) &&
0418             (padapter->securitypriv.PrivacyAlgrthm != _WEP104_)) {
0419             /* restructure_ht_ie */
0420             r8712_restructure_ht_ie(padapter,
0421                         &pnetwork->network.IEs[0],
0422                         &psecnetwork->IEs[0],
0423                         pnetwork->network.IELength,
0424                         &psecnetwork->IELength);
0425         }
0426     }
0427     psecuritypriv->supplicant_ie[0] = (u8)psecnetwork->IELength;
0428     if (psecnetwork->IELength < 255)
0429         memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0],
0430             psecnetwork->IELength);
0431     else
0432         memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0],
0433             255);
0434     /* get cmdsz before endian conversion */
0435     pcmd->cmdsz = r8712_get_wlan_bssid_ex_sz(psecnetwork);
0436 #ifdef __BIG_ENDIAN
0437     /* wlan_network endian conversion */
0438     psecnetwork->Length = cpu_to_le32(psecnetwork->Length);
0439     psecnetwork->Ssid.SsidLength = cpu_to_le32(
0440                        psecnetwork->Ssid.SsidLength);
0441     psecnetwork->Privacy = cpu_to_le32(psecnetwork->Privacy);
0442     psecnetwork->Rssi = cpu_to_le32(psecnetwork->Rssi);
0443     psecnetwork->NetworkTypeInUse = cpu_to_le32(
0444                     psecnetwork->NetworkTypeInUse);
0445     psecnetwork->Configuration.ATIMWindow = cpu_to_le32(
0446                 psecnetwork->Configuration.ATIMWindow);
0447     psecnetwork->Configuration.BeaconPeriod = cpu_to_le32(
0448                  psecnetwork->Configuration.BeaconPeriod);
0449     psecnetwork->Configuration.DSConfig = cpu_to_le32(
0450                 psecnetwork->Configuration.DSConfig);
0451     psecnetwork->Configuration.FHConfig.DwellTime = cpu_to_le32(
0452                 psecnetwork->Configuration.FHConfig.DwellTime);
0453     psecnetwork->Configuration.FHConfig.HopPattern = cpu_to_le32(
0454                 psecnetwork->Configuration.FHConfig.HopPattern);
0455     psecnetwork->Configuration.FHConfig.HopSet = cpu_to_le32(
0456                 psecnetwork->Configuration.FHConfig.HopSet);
0457     psecnetwork->Configuration.FHConfig.Length = cpu_to_le32(
0458                 psecnetwork->Configuration.FHConfig.Length);
0459     psecnetwork->Configuration.Length = cpu_to_le32(
0460                 psecnetwork->Configuration.Length);
0461     psecnetwork->InfrastructureMode = cpu_to_le32(
0462                 psecnetwork->InfrastructureMode);
0463     psecnetwork->IELength = cpu_to_le32(psecnetwork->IELength);
0464 #endif
0465     INIT_LIST_HEAD(&pcmd->list);
0466     pcmd->cmdcode = _JoinBss_CMD_;
0467     pcmd->parmbuf = (unsigned char *)psecnetwork;
0468     pcmd->rsp = NULL;
0469     pcmd->rspsz = 0;
0470     r8712_enqueue_cmd(pcmdpriv, pcmd);
0471     return 0;
0472 }
0473 
0474 void r8712_disassoc_cmd(struct _adapter *padapter) /* for sta_mode */
0475 {
0476     struct cmd_obj *pdisconnect_cmd;
0477     struct disconnect_parm *pdisconnect;
0478     struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
0479 
0480     pdisconnect_cmd = kmalloc(sizeof(*pdisconnect_cmd), GFP_ATOMIC);
0481     if (!pdisconnect_cmd)
0482         return;
0483     pdisconnect = kmalloc(sizeof(*pdisconnect), GFP_ATOMIC);
0484     if (!pdisconnect) {
0485         kfree(pdisconnect_cmd);
0486         return;
0487     }
0488     init_h2fwcmd_w_parm_no_rsp(pdisconnect_cmd, pdisconnect,
0489                    _DisConnect_CMD_);
0490     r8712_enqueue_cmd(pcmdpriv, pdisconnect_cmd);
0491 }
0492 
0493 void r8712_setopmode_cmd(struct _adapter *padapter,
0494          enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype)
0495 {
0496     struct cmd_obj *ph2c;
0497     struct setopmode_parm *psetop;
0498 
0499     struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
0500 
0501     ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
0502     if (!ph2c)
0503         return;
0504     psetop = kmalloc(sizeof(*psetop), GFP_ATOMIC);
0505     if (!psetop) {
0506         kfree(ph2c);
0507         return;
0508     }
0509     init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
0510     psetop->mode = (u8)networktype;
0511     r8712_enqueue_cmd(pcmdpriv, ph2c);
0512 }
0513 
0514 void r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key)
0515 {
0516     struct cmd_obj *ph2c;
0517     struct set_stakey_parm *psetstakey_para;
0518     struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
0519     struct set_stakey_rsp *psetstakey_rsp = NULL;
0520     struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
0521     struct security_priv *psecuritypriv = &padapter->securitypriv;
0522     struct sta_info *sta = (struct sta_info *)psta;
0523 
0524     ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
0525     if (!ph2c)
0526         return;
0527     psetstakey_para = kmalloc(sizeof(*psetstakey_para), GFP_ATOMIC);
0528     if (!psetstakey_para) {
0529         kfree(ph2c);
0530         return;
0531     }
0532     psetstakey_rsp = kmalloc(sizeof(*psetstakey_rsp), GFP_ATOMIC);
0533     if (!psetstakey_rsp) {
0534         kfree(ph2c);
0535         kfree(psetstakey_para);
0536         return;
0537     }
0538     init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
0539     ph2c->rsp = (u8 *)psetstakey_rsp;
0540     ph2c->rspsz = sizeof(struct set_stakey_rsp);
0541     ether_addr_copy(psetstakey_para->addr, sta->hwaddr);
0542     if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
0543         psetstakey_para->algorithm = (unsigned char)
0544                         psecuritypriv->PrivacyAlgrthm;
0545     else
0546         GET_ENCRY_ALGO(psecuritypriv, sta,
0547                    psetstakey_para->algorithm, false);
0548     if (unicast_key)
0549         memcpy(&psetstakey_para->key, &sta->x_UncstKey, 16);
0550     else
0551         memcpy(&psetstakey_para->key,
0552             &psecuritypriv->XGrpKey[
0553             psecuritypriv->XGrpKeyid - 1]. skey, 16);
0554     r8712_enqueue_cmd(pcmdpriv, ph2c);
0555 }
0556 
0557 void r8712_setMacAddr_cmd(struct _adapter *padapter, const u8 *mac_addr)
0558 {
0559     struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
0560     struct cmd_obj *ph2c;
0561     struct SetMacAddr_param *psetMacAddr_para;
0562 
0563     ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
0564     if (!ph2c)
0565         return;
0566     psetMacAddr_para = kmalloc(sizeof(*psetMacAddr_para), GFP_ATOMIC);
0567     if (!psetMacAddr_para) {
0568         kfree(ph2c);
0569         return;
0570     }
0571     init_h2fwcmd_w_parm_no_rsp(ph2c, psetMacAddr_para,
0572                    _SetMacAddress_CMD_);
0573     ether_addr_copy(psetMacAddr_para->MacAddr, mac_addr);
0574     r8712_enqueue_cmd(pcmdpriv, ph2c);
0575 }
0576 
0577 void r8712_addbareq_cmd(struct _adapter *padapter, u8 tid)
0578 {
0579     struct cmd_priv     *pcmdpriv = &padapter->cmdpriv;
0580     struct cmd_obj      *ph2c;
0581     struct addBaReq_parm    *paddbareq_parm;
0582 
0583     ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
0584     if (!ph2c)
0585         return;
0586     paddbareq_parm = kmalloc(sizeof(*paddbareq_parm), GFP_ATOMIC);
0587     if (!paddbareq_parm) {
0588         kfree(ph2c);
0589         return;
0590     }
0591     paddbareq_parm->tid = tid;
0592     init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm,
0593                    GEN_CMD_CODE(_AddBAReq));
0594     r8712_enqueue_cmd_ex(pcmdpriv, ph2c);
0595 }
0596 
0597 void r8712_wdg_wk_cmd(struct _adapter *padapter)
0598 {
0599     struct cmd_obj *ph2c;
0600     struct drvint_cmd_parm  *pdrvintcmd_param;
0601     struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
0602 
0603     ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
0604     if (!ph2c)
0605         return;
0606     pdrvintcmd_param = kmalloc(sizeof(*pdrvintcmd_param), GFP_ATOMIC);
0607     if (!pdrvintcmd_param) {
0608         kfree(ph2c);
0609         return;
0610     }
0611     pdrvintcmd_param->i_cid = WDG_WK_CID;
0612     pdrvintcmd_param->sz = 0;
0613     pdrvintcmd_param->pbuf = NULL;
0614     init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvintcmd_param, _DRV_INT_CMD_);
0615     r8712_enqueue_cmd_ex(pcmdpriv, ph2c);
0616 }
0617 
0618 void r8712_survey_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd)
0619 {
0620     struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
0621 
0622     if (pcmd->res != H2C_SUCCESS)
0623         clr_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
0624     r8712_free_cmd_obj(pcmd);
0625 }
0626 
0627 void r8712_disassoc_cmd_callback(struct _adapter *padapter,
0628                  struct cmd_obj *pcmd)
0629 {
0630     unsigned long irqL;
0631     struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
0632 
0633     if (pcmd->res != H2C_SUCCESS) {
0634         spin_lock_irqsave(&pmlmepriv->lock, irqL);
0635         set_fwstate(pmlmepriv, _FW_LINKED);
0636         spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
0637         return;
0638     }
0639     r8712_free_cmd_obj(pcmd);
0640 }
0641 
0642 void r8712_joinbss_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd)
0643 {
0644     struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
0645 
0646     if (pcmd->res != H2C_SUCCESS)
0647         mod_timer(&pmlmepriv->assoc_timer,
0648               jiffies + msecs_to_jiffies(1));
0649     r8712_free_cmd_obj(pcmd);
0650 }
0651 
0652 void r8712_createbss_cmd_callback(struct _adapter *padapter,
0653                   struct cmd_obj *pcmd)
0654 {
0655     unsigned long irqL;
0656     struct sta_info *psta = NULL;
0657     struct wlan_network *pwlan = NULL;
0658     struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
0659     struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf;
0660     struct wlan_network *tgt_network = &(pmlmepriv->cur_network);
0661 
0662     if (pcmd->res != H2C_SUCCESS)
0663         mod_timer(&pmlmepriv->assoc_timer,
0664               jiffies + msecs_to_jiffies(1));
0665     del_timer(&pmlmepriv->assoc_timer);
0666 #ifdef __BIG_ENDIAN
0667     /* endian_convert */
0668     pnetwork->Length = le32_to_cpu(pnetwork->Length);
0669     pnetwork->Ssid.SsidLength = le32_to_cpu(pnetwork->Ssid.SsidLength);
0670     pnetwork->Privacy = le32_to_cpu(pnetwork->Privacy);
0671     pnetwork->Rssi = le32_to_cpu(pnetwork->Rssi);
0672     pnetwork->NetworkTypeInUse = le32_to_cpu(pnetwork->NetworkTypeInUse);
0673     pnetwork->Configuration.ATIMWindow =
0674         le32_to_cpu(pnetwork->Configuration.ATIMWindow);
0675     pnetwork->Configuration.DSConfig =
0676         le32_to_cpu(pnetwork->Configuration.DSConfig);
0677     pnetwork->Configuration.FHConfig.DwellTime =
0678         le32_to_cpu(pnetwork->Configuration.FHConfig.DwellTime);
0679     pnetwork->Configuration.FHConfig.HopPattern =
0680         le32_to_cpu(pnetwork->Configuration.FHConfig.HopPattern);
0681     pnetwork->Configuration.FHConfig.HopSet =
0682         le32_to_cpu(pnetwork->Configuration.FHConfig.HopSet);
0683     pnetwork->Configuration.FHConfig.Length =
0684         le32_to_cpu(pnetwork->Configuration.FHConfig.Length);
0685     pnetwork->Configuration.Length =
0686         le32_to_cpu(pnetwork->Configuration.Length);
0687     pnetwork->InfrastructureMode =
0688         le32_to_cpu(pnetwork->InfrastructureMode);
0689     pnetwork->IELength = le32_to_cpu(pnetwork->IELength);
0690 #endif
0691     spin_lock_irqsave(&pmlmepriv->lock, irqL);
0692     if ((pmlmepriv->fw_state) & WIFI_AP_STATE) {
0693         psta = r8712_get_stainfo(&padapter->stapriv,
0694                      pnetwork->MacAddress);
0695         if (!psta) {
0696             psta = r8712_alloc_stainfo(&padapter->stapriv,
0697                            pnetwork->MacAddress);
0698             if (!psta)
0699                 goto createbss_cmd_fail;
0700         }
0701         r8712_indicate_connect(padapter);
0702     } else {
0703         pwlan = _r8712_alloc_network(pmlmepriv);
0704         if (!pwlan) {
0705             pwlan = r8712_get_oldest_wlan_network(
0706                 &pmlmepriv->scanned_queue);
0707             if (!pwlan)
0708                 goto createbss_cmd_fail;
0709             pwlan->last_scanned = jiffies;
0710         } else {
0711             list_add_tail(&(pwlan->list),
0712                      &pmlmepriv->scanned_queue.queue);
0713         }
0714         pnetwork->Length = r8712_get_wlan_bssid_ex_sz(pnetwork);
0715         memcpy(&(pwlan->network), pnetwork, pnetwork->Length);
0716         pwlan->fixed = true;
0717         memcpy(&tgt_network->network, pnetwork,
0718             (r8712_get_wlan_bssid_ex_sz(pnetwork)));
0719         if (pmlmepriv->fw_state & _FW_UNDER_LINKING)
0720             pmlmepriv->fw_state ^= _FW_UNDER_LINKING;
0721         /*
0722          * we will set _FW_LINKED when there is one more sat to
0723          * join us (stassoc_event_callback)
0724          */
0725     }
0726 createbss_cmd_fail:
0727     spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
0728     r8712_free_cmd_obj(pcmd);
0729 }
0730 
0731 void r8712_setstaKey_cmdrsp_callback(struct _adapter *padapter,
0732                      struct cmd_obj *pcmd)
0733 {
0734     struct sta_priv *pstapriv = &padapter->stapriv;
0735     struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *)
0736                         (pcmd->rsp);
0737     struct sta_info *psta = r8712_get_stainfo(pstapriv,
0738                           psetstakey_rsp->addr);
0739 
0740     if (!psta)
0741         goto exit;
0742     psta->aid = psta->mac_id = psetstakey_rsp->keyid; /*CAM_ID(CAM_ENTRY)*/
0743 exit:
0744     r8712_free_cmd_obj(pcmd);
0745 }
0746 
0747 void r8712_setassocsta_cmdrsp_callback(struct _adapter *padapter,
0748                        struct cmd_obj *pcmd)
0749 {
0750     unsigned long   irqL;
0751     struct sta_priv *pstapriv = &padapter->stapriv;
0752     struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
0753     struct set_assocsta_parm *passocsta_parm =
0754                 (struct set_assocsta_parm *)(pcmd->parmbuf);
0755     struct set_assocsta_rsp *passocsta_rsp =
0756                 (struct set_assocsta_rsp *) (pcmd->rsp);
0757     struct sta_info *psta = r8712_get_stainfo(pstapriv,
0758                           passocsta_parm->addr);
0759 
0760     if (!psta)
0761         return;
0762     psta->aid = psta->mac_id = passocsta_rsp->cam_id;
0763     spin_lock_irqsave(&pmlmepriv->lock, irqL);
0764     if ((check_fwstate(pmlmepriv, WIFI_MP_STATE)) &&
0765         (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)))
0766         pmlmepriv->fw_state ^= _FW_UNDER_LINKING;
0767     set_fwstate(pmlmepriv, _FW_LINKED);
0768     spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
0769     r8712_free_cmd_obj(pcmd);
0770 }
0771 
0772 void r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
0773             u32 tryPktCnt, u32 tryPktInterval, u32 firstStageTO)
0774 {
0775     struct cmd_obj *ph2c;
0776     struct DisconnectCtrlEx_param *param;
0777     struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
0778 
0779     ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
0780     if (!ph2c)
0781         return;
0782     param = kzalloc(sizeof(*param), GFP_ATOMIC);
0783     if (!param) {
0784         kfree(ph2c);
0785         return;
0786     }
0787 
0788     param->EnableDrvCtrl = (unsigned char)enableDrvCtrl;
0789     param->TryPktCnt = (unsigned char)tryPktCnt;
0790     param->TryPktInterval = (unsigned char)tryPktInterval;
0791     param->FirstStageTO = (unsigned int)firstStageTO;
0792 
0793     init_h2fwcmd_w_parm_no_rsp(ph2c, param,
0794                 GEN_CMD_CODE(_DisconnectCtrlEx));
0795     r8712_enqueue_cmd(pcmdpriv, ph2c);
0796 }