linux/drivers/net/wireless/libertas/cmdresp.c
<<
>>
Prefs
   1/**
   2  * This file contains the handling of command
   3  * responses as well as events generated by firmware.
   4  */
   5#include <linux/delay.h>
   6#include <linux/if_arp.h>
   7#include <linux/netdevice.h>
   8
   9#include <net/iw_handler.h>
  10
  11#include "host.h"
  12#include "decl.h"
  13#include "defs.h"
  14#include "dev.h"
  15#include "join.h"
  16#include "wext.h"
  17
  18/**
  19 *  @brief This function handles disconnect event. it
  20 *  reports disconnect to upper layer, clean tx/rx packets,
  21 *  reset link state etc.
  22 *
  23 *  @param priv    A pointer to struct lbs_private structure
  24 *  @return        n/a
  25 */
  26void lbs_mac_event_disconnected(struct lbs_private *priv)
  27{
  28        union iwreq_data wrqu;
  29
  30        if (priv->connect_status != LBS_CONNECTED)
  31                return;
  32
  33        lbs_deb_enter(LBS_DEB_ASSOC);
  34
  35        memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
  36        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
  37
  38        /*
  39         * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
  40         * It causes problem in the Supplicant
  41         */
  42
  43        msleep_interruptible(1000);
  44        wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
  45
  46        /* report disconnect to upper layer */
  47        netif_stop_queue(priv->dev);
  48        netif_carrier_off(priv->dev);
  49
  50        /* Free Tx and Rx packets */
  51        kfree_skb(priv->currenttxskb);
  52        priv->currenttxskb = NULL;
  53        priv->tx_pending_len = 0;
  54
  55        /* reset SNR/NF/RSSI values */
  56        memset(priv->SNR, 0x00, sizeof(priv->SNR));
  57        memset(priv->NF, 0x00, sizeof(priv->NF));
  58        memset(priv->RSSI, 0x00, sizeof(priv->RSSI));
  59        memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
  60        memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
  61        priv->nextSNRNF = 0;
  62        priv->numSNRNF = 0;
  63        priv->connect_status = LBS_DISCONNECTED;
  64
  65        /* Clear out associated SSID and BSSID since connection is
  66         * no longer valid.
  67         */
  68        memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
  69        memset(&priv->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE);
  70        priv->curbssparams.ssid_len = 0;
  71
  72        if (priv->psstate != PS_STATE_FULL_POWER) {
  73                /* make firmware to exit PS mode */
  74                lbs_deb_cmd("disconnected, so exit PS mode\n");
  75                lbs_ps_wakeup(priv, 0);
  76        }
  77        lbs_deb_leave(LBS_DEB_CMD);
  78}
  79
  80/**
  81 *  @brief This function handles MIC failure event.
  82 *
  83 *  @param priv    A pointer to struct lbs_private structure
  84 *  @para  event   the event id
  85 *  @return        n/a
  86 */
  87static void handle_mic_failureevent(struct lbs_private *priv, u32 event)
  88{
  89        char buf[50];
  90
  91        lbs_deb_enter(LBS_DEB_CMD);
  92        memset(buf, 0, sizeof(buf));
  93
  94        sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
  95
  96        if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) {
  97                strcat(buf, "unicast ");
  98        } else {
  99                strcat(buf, "multicast ");
 100        }
 101
 102        lbs_send_iwevcustom_event(priv, buf);
 103        lbs_deb_leave(LBS_DEB_CMD);
 104}
 105
 106static int lbs_ret_reg_access(struct lbs_private *priv,
 107                               u16 type, struct cmd_ds_command *resp)
 108{
 109        int ret = 0;
 110
 111        lbs_deb_enter(LBS_DEB_CMD);
 112
 113        switch (type) {
 114        case CMD_RET(CMD_MAC_REG_ACCESS):
 115                {
 116                        struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
 117
 118                        priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
 119                        priv->offsetvalue.value = le32_to_cpu(reg->value);
 120                        break;
 121                }
 122
 123        case CMD_RET(CMD_BBP_REG_ACCESS):
 124                {
 125                        struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
 126
 127                        priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
 128                        priv->offsetvalue.value = reg->value;
 129                        break;
 130                }
 131
 132        case CMD_RET(CMD_RF_REG_ACCESS):
 133                {
 134                        struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
 135
 136                        priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
 137                        priv->offsetvalue.value = reg->value;
 138                        break;
 139                }
 140
 141        default:
 142                ret = -1;
 143        }
 144
 145        lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
 146        return ret;
 147}
 148
 149static int lbs_ret_802_11_stat(struct lbs_private *priv,
 150                                struct cmd_ds_command *resp)
 151{
 152        lbs_deb_enter(LBS_DEB_CMD);
 153/*      currently priv->wlan802_11Stat is unused
 154
 155        struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;
 156
 157        // TODO Convert it to Big endian befor copy
 158        memcpy(&priv->wlan802_11Stat,
 159               p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
 160*/
 161        lbs_deb_leave(LBS_DEB_CMD);
 162        return 0;
 163}
 164
 165static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv,
 166                                    struct cmd_ds_command *resp)
 167{
 168        struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
 169        u16 oid = le16_to_cpu(smib->oid);
 170        u16 querytype = le16_to_cpu(smib->querytype);
 171
 172        lbs_deb_enter(LBS_DEB_CMD);
 173
 174        lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid,
 175               querytype);
 176        lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize));
 177
 178        if (querytype == CMD_ACT_GET) {
 179                switch (oid) {
 180                case FRAGTHRESH_I:
 181                        priv->fragthsd =
 182                                le16_to_cpu(*((__le16 *)(smib->value)));
 183                        lbs_deb_cmd("SNMP_RESP: frag threshold %u\n",
 184                                    priv->fragthsd);
 185                        break;
 186                case RTSTHRESH_I:
 187                        priv->rtsthsd =
 188                                le16_to_cpu(*((__le16 *)(smib->value)));
 189                        lbs_deb_cmd("SNMP_RESP: rts threshold %u\n",
 190                                    priv->rtsthsd);
 191                        break;
 192                case SHORT_RETRYLIM_I:
 193                        priv->txretrycount =
 194                                le16_to_cpu(*((__le16 *)(smib->value)));
 195                        lbs_deb_cmd("SNMP_RESP: tx retry count %u\n",
 196                                    priv->rtsthsd);
 197                        break;
 198                default:
 199                        break;
 200                }
 201        }
 202
 203        lbs_deb_enter(LBS_DEB_CMD);
 204        return 0;
 205}
 206
 207static int lbs_ret_802_11_key_material(struct lbs_private *priv,
 208                                        struct cmd_ds_command *resp)
 209{
 210        struct cmd_ds_802_11_key_material *pkeymaterial =
 211            &resp->params.keymaterial;
 212        u16 action = le16_to_cpu(pkeymaterial->action);
 213
 214        lbs_deb_enter(LBS_DEB_CMD);
 215
 216        /* Copy the returned key to driver private data */
 217        if (action == CMD_ACT_GET) {
 218                u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
 219                u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));
 220
 221                while (buf_ptr < resp_end) {
 222                        struct MrvlIEtype_keyParamSet * pkeyparamset =
 223                            (struct MrvlIEtype_keyParamSet *) buf_ptr;
 224                        struct enc_key * pkey;
 225                        u16 param_set_len = le16_to_cpu(pkeyparamset->length);
 226                        u16 key_len = le16_to_cpu(pkeyparamset->keylen);
 227                        u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo);
 228                        u16 key_type = le16_to_cpu(pkeyparamset->keytypeid);
 229                        u8 * end;
 230
 231                        end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
 232                                                  + sizeof (pkeyparamset->length)
 233                                                  + param_set_len;
 234                        /* Make sure we don't access past the end of the IEs */
 235                        if (end > resp_end)
 236                                break;
 237
 238                        if (key_flags & KEY_INFO_WPA_UNICAST)
 239                                pkey = &priv->wpa_unicast_key;
 240                        else if (key_flags & KEY_INFO_WPA_MCAST)
 241                                pkey = &priv->wpa_mcast_key;
 242                        else
 243                                break;
 244
 245                        /* Copy returned key into driver */
 246                        memset(pkey, 0, sizeof(struct enc_key));
 247                        if (key_len > sizeof(pkey->key))
 248                                break;
 249                        pkey->type = key_type;
 250                        pkey->flags = key_flags;
 251                        pkey->len = key_len;
 252                        memcpy(pkey->key, pkeyparamset->key, pkey->len);
 253
 254                        buf_ptr = end + 1;
 255                }
 256        }
 257
 258        lbs_deb_enter(LBS_DEB_CMD);
 259        return 0;
 260}
 261
 262static int lbs_ret_802_11_mac_address(struct lbs_private *priv,
 263                                       struct cmd_ds_command *resp)
 264{
 265        struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd;
 266
 267        lbs_deb_enter(LBS_DEB_CMD);
 268
 269        memcpy(priv->current_addr, macadd->macadd, ETH_ALEN);
 270
 271        lbs_deb_enter(LBS_DEB_CMD);
 272        return 0;
 273}
 274
 275static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv,
 276                                       struct cmd_ds_command *resp)
 277{
 278        struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;
 279
 280        lbs_deb_enter(LBS_DEB_CMD);
 281
 282        priv->txpowerlevel = le16_to_cpu(rtp->currentlevel);
 283
 284        lbs_deb_cmd("TX power currently %d\n", priv->txpowerlevel);
 285
 286        lbs_deb_leave(LBS_DEB_CMD);
 287        return 0;
 288}
 289
 290static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv,
 291                                              struct cmd_ds_command *resp)
 292{
 293        struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset;
 294
 295        lbs_deb_enter(LBS_DEB_CMD);
 296
 297        if (rates->action == CMD_ACT_GET) {
 298                priv->enablehwauto = le16_to_cpu(rates->enablehwauto);
 299                priv->ratebitmap = le16_to_cpu(rates->bitmap);
 300        }
 301
 302        lbs_deb_leave(LBS_DEB_CMD);
 303        return 0;
 304}
 305
 306static int lbs_ret_802_11_rssi(struct lbs_private *priv,
 307                                struct cmd_ds_command *resp)
 308{
 309        struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
 310
 311        lbs_deb_enter(LBS_DEB_CMD);
 312
 313        /* store the non average value */
 314        priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
 315        priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
 316
 317        priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
 318        priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor);
 319
 320        priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
 321            CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
 322                     priv->NF[TYPE_BEACON][TYPE_NOAVG]);
 323
 324        priv->RSSI[TYPE_BEACON][TYPE_AVG] =
 325            CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
 326                     priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
 327
 328        lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
 329               priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
 330               priv->RSSI[TYPE_BEACON][TYPE_AVG]);
 331
 332        lbs_deb_leave(LBS_DEB_CMD);
 333        return 0;
 334}
 335
 336static int lbs_ret_802_11_eeprom_access(struct lbs_private *priv,
 337                                  struct cmd_ds_command *resp)
 338{
 339        struct lbs_ioctl_regrdwr *pbuf;
 340        pbuf = (struct lbs_ioctl_regrdwr *) priv->prdeeprom;
 341
 342        lbs_deb_enter_args(LBS_DEB_CMD, "len %d",
 343               le16_to_cpu(resp->params.rdeeprom.bytecount));
 344        if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
 345                pbuf->NOB = 0;
 346                lbs_deb_cmd("EEPROM read length too big\n");
 347                return -1;
 348        }
 349        pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount);
 350        if (pbuf->NOB > 0) {
 351
 352                memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value,
 353                       le16_to_cpu(resp->params.rdeeprom.bytecount));
 354                lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value,
 355                        le16_to_cpu(resp->params.rdeeprom.bytecount));
 356        }
 357        lbs_deb_leave(LBS_DEB_CMD);
 358        return 0;
 359}
 360
 361static int lbs_ret_get_log(struct lbs_private *priv,
 362                            struct cmd_ds_command *resp)
 363{
 364        struct cmd_ds_802_11_get_log *logmessage = &resp->params.glog;
 365
 366        lbs_deb_enter(LBS_DEB_CMD);
 367
 368        /* Stored little-endian */
 369        memcpy(&priv->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log));
 370
 371        lbs_deb_leave(LBS_DEB_CMD);
 372        return 0;
 373}
 374
 375static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv,
 376                                        struct cmd_ds_command *resp)
 377{
 378        struct cmd_ds_802_11_beacon_control *bcn_ctrl =
 379            &resp->params.bcn_ctrl;
 380
 381        lbs_deb_enter(LBS_DEB_CMD);
 382
 383        if (bcn_ctrl->action == CMD_ACT_GET) {
 384                priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
 385                priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
 386        }
 387
 388        lbs_deb_enter(LBS_DEB_CMD);
 389        return 0;
 390}
 391
 392static inline int handle_cmd_response(struct lbs_private *priv,
 393                                      unsigned long dummy,
 394                                      struct cmd_header *cmd_response)
 395{
 396        struct cmd_ds_command *resp = (struct cmd_ds_command *) cmd_response;
 397        int ret = 0;
 398        unsigned long flags;
 399        uint16_t respcmd = le16_to_cpu(resp->command);
 400
 401        lbs_deb_enter(LBS_DEB_HOST);
 402
 403        switch (respcmd) {
 404        case CMD_RET(CMD_MAC_REG_ACCESS):
 405        case CMD_RET(CMD_BBP_REG_ACCESS):
 406        case CMD_RET(CMD_RF_REG_ACCESS):
 407                ret = lbs_ret_reg_access(priv, respcmd, resp);
 408                break;
 409
 410        case CMD_RET(CMD_802_11_SCAN):
 411                ret = lbs_ret_80211_scan(priv, resp);
 412                break;
 413
 414        case CMD_RET(CMD_802_11_GET_LOG):
 415                ret = lbs_ret_get_log(priv, resp);
 416                break;
 417
 418        case CMD_RET_802_11_ASSOCIATE:
 419        case CMD_RET(CMD_802_11_ASSOCIATE):
 420        case CMD_RET(CMD_802_11_REASSOCIATE):
 421                ret = lbs_ret_80211_associate(priv, resp);
 422                break;
 423
 424        case CMD_RET(CMD_802_11_DISASSOCIATE):
 425        case CMD_RET(CMD_802_11_DEAUTHENTICATE):
 426                ret = lbs_ret_80211_disassociate(priv, resp);
 427                break;
 428
 429        case CMD_RET(CMD_802_11_AD_HOC_START):
 430        case CMD_RET(CMD_802_11_AD_HOC_JOIN):
 431                ret = lbs_ret_80211_ad_hoc_start(priv, resp);
 432                break;
 433
 434        case CMD_RET(CMD_802_11_GET_STAT):
 435                ret = lbs_ret_802_11_stat(priv, resp);
 436                break;
 437
 438        case CMD_RET(CMD_802_11_SNMP_MIB):
 439                ret = lbs_ret_802_11_snmp_mib(priv, resp);
 440                break;
 441
 442        case CMD_RET(CMD_802_11_RF_TX_POWER):
 443                ret = lbs_ret_802_11_rf_tx_power(priv, resp);
 444                break;
 445
 446        case CMD_RET(CMD_802_11_SET_AFC):
 447        case CMD_RET(CMD_802_11_GET_AFC):
 448                spin_lock_irqsave(&priv->driver_lock, flags);
 449                memmove((void *)priv->cur_cmd->callback_arg, &resp->params.afc,
 450                        sizeof(struct cmd_ds_802_11_afc));
 451                spin_unlock_irqrestore(&priv->driver_lock, flags);
 452
 453                break;
 454
 455        case CMD_RET(CMD_MAC_MULTICAST_ADR):
 456        case CMD_RET(CMD_MAC_CONTROL):
 457        case CMD_RET(CMD_802_11_RESET):
 458        case CMD_RET(CMD_802_11_AUTHENTICATE):
 459        case CMD_RET(CMD_802_11_BEACON_STOP):
 460                break;
 461
 462        case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
 463                ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp);
 464                break;
 465
 466        case CMD_RET(CMD_802_11_RSSI):
 467                ret = lbs_ret_802_11_rssi(priv, resp);
 468                break;
 469
 470        case CMD_RET(CMD_802_11_MAC_ADDRESS):
 471                ret = lbs_ret_802_11_mac_address(priv, resp);
 472                break;
 473
 474        case CMD_RET(CMD_802_11_AD_HOC_STOP):
 475                ret = lbs_ret_80211_ad_hoc_stop(priv, resp);
 476                break;
 477
 478        case CMD_RET(CMD_802_11_KEY_MATERIAL):
 479                ret = lbs_ret_802_11_key_material(priv, resp);
 480                break;
 481
 482        case CMD_RET(CMD_802_11_EEPROM_ACCESS):
 483                ret = lbs_ret_802_11_eeprom_access(priv, resp);
 484                break;
 485
 486        case CMD_RET(CMD_802_11D_DOMAIN_INFO):
 487                ret = lbs_ret_802_11d_domain_info(priv, resp);
 488                break;
 489
 490        case CMD_RET(CMD_802_11_TPC_CFG):
 491                spin_lock_irqsave(&priv->driver_lock, flags);
 492                memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
 493                        sizeof(struct cmd_ds_802_11_tpc_cfg));
 494                spin_unlock_irqrestore(&priv->driver_lock, flags);
 495                break;
 496        case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
 497                spin_lock_irqsave(&priv->driver_lock, flags);
 498                memmove((void *)priv->cur_cmd->callback_arg, &resp->params.ledgpio,
 499                        sizeof(struct cmd_ds_802_11_led_ctrl));
 500                spin_unlock_irqrestore(&priv->driver_lock, flags);
 501                break;
 502
 503        case CMD_RET(CMD_802_11_PWR_CFG):
 504                spin_lock_irqsave(&priv->driver_lock, flags);
 505                memmove((void *)priv->cur_cmd->callback_arg, &resp->params.pwrcfg,
 506                        sizeof(struct cmd_ds_802_11_pwr_cfg));
 507                spin_unlock_irqrestore(&priv->driver_lock, flags);
 508
 509                break;
 510
 511        case CMD_RET(CMD_GET_TSF):
 512                spin_lock_irqsave(&priv->driver_lock, flags);
 513                memcpy((void *)priv->cur_cmd->callback_arg,
 514                       &resp->params.gettsf.tsfvalue, sizeof(u64));
 515                spin_unlock_irqrestore(&priv->driver_lock, flags);
 516                break;
 517        case CMD_RET(CMD_BT_ACCESS):
 518                spin_lock_irqsave(&priv->driver_lock, flags);
 519                if (priv->cur_cmd->callback_arg)
 520                        memcpy((void *)priv->cur_cmd->callback_arg,
 521                               &resp->params.bt.addr1, 2 * ETH_ALEN);
 522                spin_unlock_irqrestore(&priv->driver_lock, flags);
 523                break;
 524        case CMD_RET(CMD_FWT_ACCESS):
 525                spin_lock_irqsave(&priv->driver_lock, flags);
 526                if (priv->cur_cmd->callback_arg)
 527                        memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.fwt,
 528                               sizeof(resp->params.fwt));
 529                spin_unlock_irqrestore(&priv->driver_lock, flags);
 530                break;
 531        case CMD_RET(CMD_802_11_BEACON_CTRL):
 532                ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
 533                break;
 534
 535        default:
 536                lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
 537                             le16_to_cpu(resp->command));
 538                break;
 539        }
 540        lbs_deb_leave(LBS_DEB_HOST);
 541        return ret;
 542}
 543
 544int lbs_process_rx_command(struct lbs_private *priv)
 545{
 546        uint16_t respcmd, curcmd;
 547        struct cmd_header *resp;
 548        int ret = 0;
 549        unsigned long flags;
 550        uint16_t result;
 551
 552        lbs_deb_enter(LBS_DEB_HOST);
 553
 554        mutex_lock(&priv->lock);
 555        spin_lock_irqsave(&priv->driver_lock, flags);
 556
 557        if (!priv->cur_cmd) {
 558                lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
 559                ret = -1;
 560                spin_unlock_irqrestore(&priv->driver_lock, flags);
 561                goto done;
 562        }
 563
 564        resp = (void *)priv->upld_buf;
 565        curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
 566        respcmd = le16_to_cpu(resp->command);
 567        result = le16_to_cpu(resp->result);
 568
 569        lbs_deb_host("CMD_RESP: response 0x%04x, seq %d, size %d, jiffies %lu\n",
 570                     respcmd, le16_to_cpu(resp->seqnum), priv->upld_len, jiffies);
 571        lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len);
 572
 573        if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
 574                lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
 575                            le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
 576                spin_unlock_irqrestore(&priv->driver_lock, flags);
 577                ret = -1;
 578                goto done;
 579        }
 580        if (respcmd != CMD_RET(curcmd) &&
 581            respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) {
 582                lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
 583                spin_unlock_irqrestore(&priv->driver_lock, flags);
 584                ret = -1;
 585                goto done;
 586        }
 587
 588        if (resp->result == cpu_to_le16(0x0004)) {
 589                /* 0x0004 means -EAGAIN. Drop the response, let it time out
 590                   and be resubmitted */
 591                lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n",
 592                            le16_to_cpu(resp->command));
 593                spin_unlock_irqrestore(&priv->driver_lock, flags);
 594                ret = -1;
 595                goto done;
 596        }
 597
 598        /* Now we got response from FW, cancel the command timer */
 599        del_timer(&priv->command_timer);
 600        priv->cmd_timed_out = 0;
 601        if (priv->nr_retries) {
 602                lbs_pr_info("Received result %x to command %x after %d retries\n",
 603                            result, curcmd, priv->nr_retries);
 604                priv->nr_retries = 0;
 605        }
 606
 607        /* Store the response code to cur_cmd_retcode. */
 608        priv->cur_cmd_retcode = result;
 609
 610        if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
 611                struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1];
 612                u16 action = le16_to_cpu(psmode->action);
 613
 614                lbs_deb_host(
 615                       "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
 616                       result, action);
 617
 618                if (result) {
 619                        lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
 620                                    result);
 621                        /*
 622                         * We should not re-try enter-ps command in
 623                         * ad-hoc mode. It takes place in
 624                         * lbs_execute_next_command().
 625                         */
 626                        if (priv->mode == IW_MODE_ADHOC &&
 627                            action == CMD_SUBCMD_ENTER_PS)
 628                                priv->psmode = LBS802_11POWERMODECAM;
 629                } else if (action == CMD_SUBCMD_ENTER_PS) {
 630                        priv->needtowakeup = 0;
 631                        priv->psstate = PS_STATE_AWAKE;
 632
 633                        lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
 634                        if (priv->connect_status != LBS_CONNECTED) {
 635                                /*
 636                                 * When Deauth Event received before Enter_PS command
 637                                 * response, We need to wake up the firmware.
 638                                 */
 639                                lbs_deb_host(
 640                                       "disconnected, invoking lbs_ps_wakeup\n");
 641
 642                                spin_unlock_irqrestore(&priv->driver_lock, flags);
 643                                mutex_unlock(&priv->lock);
 644                                lbs_ps_wakeup(priv, 0);
 645                                mutex_lock(&priv->lock);
 646                                spin_lock_irqsave(&priv->driver_lock, flags);
 647                        }
 648                } else if (action == CMD_SUBCMD_EXIT_PS) {
 649                        priv->needtowakeup = 0;
 650                        priv->psstate = PS_STATE_FULL_POWER;
 651                        lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
 652                } else {
 653                        lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
 654                }
 655
 656                lbs_complete_command(priv, priv->cur_cmd, result);
 657                spin_unlock_irqrestore(&priv->driver_lock, flags);
 658
 659                ret = 0;
 660                goto done;
 661        }
 662
 663        /* If the command is not successful, cleanup and return failure */
 664        if ((result != 0 || !(respcmd & 0x8000))) {
 665                lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
 666                       result, respcmd);
 667                /*
 668                 * Handling errors here
 669                 */
 670                switch (respcmd) {
 671                case CMD_RET(CMD_GET_HW_SPEC):
 672                case CMD_RET(CMD_802_11_RESET):
 673                        lbs_deb_host("CMD_RESP: reset failed\n");
 674                        break;
 675
 676                }
 677                lbs_complete_command(priv, priv->cur_cmd, result);
 678                spin_unlock_irqrestore(&priv->driver_lock, flags);
 679
 680                ret = -1;
 681                goto done;
 682        }
 683
 684        spin_unlock_irqrestore(&priv->driver_lock, flags);
 685
 686        if (priv->cur_cmd && priv->cur_cmd->callback) {
 687                ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
 688                                resp);
 689        } else
 690                ret = handle_cmd_response(priv, 0, resp);
 691
 692        spin_lock_irqsave(&priv->driver_lock, flags);
 693
 694        if (priv->cur_cmd) {
 695                /* Clean up and Put current command back to cmdfreeq */
 696                lbs_complete_command(priv, priv->cur_cmd, result);
 697        }
 698        spin_unlock_irqrestore(&priv->driver_lock, flags);
 699
 700done:
 701        mutex_unlock(&priv->lock);
 702        lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
 703        return ret;
 704}
 705
 706static int lbs_send_confirmwake(struct lbs_private *priv)
 707{
 708        struct cmd_header *cmd = &priv->lbs_ps_confirm_wake;
 709        int ret = 0;
 710
 711        lbs_deb_enter(LBS_DEB_HOST);
 712
 713        cmd->command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM);
 714        cmd->size = cpu_to_le16(sizeof(*cmd));
 715        cmd->seqnum = cpu_to_le16(++priv->seqnum);
 716        cmd->result = 0;
 717
 718        lbs_deb_host("SEND_WAKEC_CMD: before download\n");
 719
 720        lbs_deb_hex(LBS_DEB_HOST, "wake confirm command", (void *)cmd, sizeof(*cmd));
 721
 722        ret = priv->hw_host_to_card(priv, MVMS_CMD, (void *)cmd, sizeof(*cmd));
 723        if (ret)
 724                lbs_pr_alert("SEND_WAKEC_CMD: Host to Card failed for Confirm Wake\n");
 725
 726        lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
 727        return ret;
 728}
 729
 730int lbs_process_event(struct lbs_private *priv)
 731{
 732        int ret = 0;
 733        u32 eventcause;
 734
 735        lbs_deb_enter(LBS_DEB_CMD);
 736
 737        spin_lock_irq(&priv->driver_lock);
 738        eventcause = priv->eventcause >> SBI_EVENT_CAUSE_SHIFT;
 739        spin_unlock_irq(&priv->driver_lock);
 740
 741        lbs_deb_cmd("event cause %d\n", eventcause);
 742
 743        switch (eventcause) {
 744        case MACREG_INT_CODE_LINK_SENSED:
 745                lbs_deb_cmd("EVENT: MACREG_INT_CODE_LINK_SENSED\n");
 746                break;
 747
 748        case MACREG_INT_CODE_DEAUTHENTICATED:
 749                lbs_deb_cmd("EVENT: deauthenticated\n");
 750                lbs_mac_event_disconnected(priv);
 751                break;
 752
 753        case MACREG_INT_CODE_DISASSOCIATED:
 754                lbs_deb_cmd("EVENT: disassociated\n");
 755                lbs_mac_event_disconnected(priv);
 756                break;
 757
 758        case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
 759                lbs_deb_cmd("EVENT: link lost\n");
 760                lbs_mac_event_disconnected(priv);
 761                break;
 762
 763        case MACREG_INT_CODE_PS_SLEEP:
 764                lbs_deb_cmd("EVENT: sleep\n");
 765
 766                /* handle unexpected PS SLEEP event */
 767                if (priv->psstate == PS_STATE_FULL_POWER) {
 768                        lbs_deb_cmd(
 769                               "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
 770                        break;
 771                }
 772                priv->psstate = PS_STATE_PRE_SLEEP;
 773
 774                lbs_ps_confirm_sleep(priv, (u16) priv->psmode);
 775
 776                break;
 777
 778        case MACREG_INT_CODE_HOST_AWAKE:
 779                lbs_deb_cmd("EVENT: HOST_AWAKE\n");
 780                lbs_send_confirmwake(priv);
 781                break;
 782
 783        case MACREG_INT_CODE_PS_AWAKE:
 784                lbs_deb_cmd("EVENT: awake\n");
 785                /* handle unexpected PS AWAKE event */
 786                if (priv->psstate == PS_STATE_FULL_POWER) {
 787                        lbs_deb_cmd(
 788                               "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
 789                        break;
 790                }
 791
 792                priv->psstate = PS_STATE_AWAKE;
 793
 794                if (priv->needtowakeup) {
 795                        /*
 796                         * wait for the command processing to finish
 797                         * before resuming sending
 798                         * priv->needtowakeup will be set to FALSE
 799                         * in lbs_ps_wakeup()
 800                         */
 801                        lbs_deb_cmd("waking up ...\n");
 802                        lbs_ps_wakeup(priv, 0);
 803                }
 804                break;
 805
 806        case MACREG_INT_CODE_MIC_ERR_UNICAST:
 807                lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
 808                handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
 809                break;
 810
 811        case MACREG_INT_CODE_MIC_ERR_MULTICAST:
 812                lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
 813                handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
 814                break;
 815        case MACREG_INT_CODE_MIB_CHANGED:
 816        case MACREG_INT_CODE_INIT_DONE:
 817                break;
 818
 819        case MACREG_INT_CODE_ADHOC_BCN_LOST:
 820                lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
 821                break;
 822
 823        case MACREG_INT_CODE_RSSI_LOW:
 824                lbs_pr_alert("EVENT: rssi low\n");
 825                break;
 826        case MACREG_INT_CODE_SNR_LOW:
 827                lbs_pr_alert("EVENT: snr low\n");
 828                break;
 829        case MACREG_INT_CODE_MAX_FAIL:
 830                lbs_pr_alert("EVENT: max fail\n");
 831                break;
 832        case MACREG_INT_CODE_RSSI_HIGH:
 833                lbs_pr_alert("EVENT: rssi high\n");
 834                break;
 835        case MACREG_INT_CODE_SNR_HIGH:
 836                lbs_pr_alert("EVENT: snr high\n");
 837                break;
 838
 839        case MACREG_INT_CODE_MESH_AUTO_STARTED:
 840                /* Ignore spurious autostart events if autostart is disabled */
 841                if (!priv->mesh_autostart_enabled) {
 842                        lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
 843                        break;
 844                }
 845                lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
 846                priv->mesh_connect_status = LBS_CONNECTED;
 847                if (priv->mesh_open) {
 848                        netif_carrier_on(priv->mesh_dev);
 849                        if (!priv->tx_pending_len)
 850                                netif_wake_queue(priv->mesh_dev);
 851                }
 852                priv->mode = IW_MODE_ADHOC;
 853                schedule_work(&priv->sync_channel);
 854                break;
 855
 856        default:
 857                lbs_pr_alert("EVENT: unknown event id %d\n", eventcause);
 858                break;
 859        }
 860
 861        spin_lock_irq(&priv->driver_lock);
 862        priv->eventcause = 0;
 863        spin_unlock_irq(&priv->driver_lock);
 864
 865        lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
 866        return ret;
 867}
 868
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.