]> Git Repo - J-linux.git/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <[email protected]>
Thu, 17 Jun 2010 20:21:14 +0000 (16:21 -0400)
committerJohn W. Linville <[email protected]>
Thu, 17 Jun 2010 20:21:14 +0000 (16:21 -0400)
Conflicts:
net/mac80211/mlme.c

1  2 
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
net/mac80211/mlme.c
net/mac80211/work.c

index 10a0acdb9dd42cf9611c83d70eb405c601a707b5,7d614c4d3c6200d5410bba749105f4d371b2e5b7..84df7fca750d01552e2d2ca2a2e7d761dc402cb5
@@@ -469,8 -469,7 +469,8 @@@ static void iwlagn_tx_cmd_build_rate(st
        }
  
        /* Set up antennas */
 -      priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
 +      priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
 +                                            priv->hw_params.valid_tx_ant);
        rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
  
        /* Set the rate in the TX cmd */
@@@ -568,7 -567,10 +568,7 @@@ int iwlagn_tx_skb(struct iwl_priv *priv
        hdr_len = ieee80211_hdrlen(fc);
  
        /* Find index into station table for destination station */
 -      if (!info->control.sta)
 -              sta_id = priv->hw_params.bcast_sta_id;
 -      else
 -              sta_id = iwl_sta_id(info->control.sta);
 +      sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
                               hdr->addr1);
        }
  
        txq_id = get_queue_from_ac(skb_get_queue_mapping(skb));
 +
 +      /* irqs already disabled/saved above when locking priv->lock */
 +      spin_lock(&priv->sta_lock);
 +
        if (ieee80211_is_data_qos(fc)) {
                qc = ieee80211_get_qos_ctl(hdr);
                tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
 -              if (unlikely(tid >= MAX_TID_COUNT))
 +              if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) {
 +                      spin_unlock(&priv->sta_lock);
                        goto drop_unlock;
 +              }
                seq_number = priv->stations[sta_id].tid[tid].seq_number;
                seq_number &= IEEE80211_SCTL_SEQ;
                hdr->seq_ctrl = hdr->seq_ctrl &
        swq_id = txq->swq_id;
        q = &txq->q;
  
 -      if (unlikely(iwl_queue_space(q) < q->high_mark))
 +      if (unlikely(iwl_queue_space(q) < q->high_mark)) {
 +              spin_unlock(&priv->sta_lock);
                goto drop_unlock;
 +      }
  
 -      if (ieee80211_is_data_qos(fc))
 +      if (ieee80211_is_data_qos(fc)) {
                priv->stations[sta_id].tid[tid].tfds_in_queue++;
 +              if (!ieee80211_has_morefrags(fc))
 +                      priv->stations[sta_id].tid[tid].seq_number = seq_number;
 +      }
 +
 +      spin_unlock(&priv->sta_lock);
  
        /* Set up driver data for this TFD */
        memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
 -      txq->txb[q->write_ptr].skb[0] = skb;
 +      txq->txb[q->write_ptr].skb = skb;
  
        /* Set up first empty entry in queue's array of Tx/cmd buffers */
        out_cmd = txq->cmd[q->write_ptr];
        txcmd_phys = pci_map_single(priv->pci_dev,
                                    &out_cmd->hdr, len,
                                    PCI_DMA_BIDIRECTIONAL);
 -      pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
 -      pci_unmap_len_set(out_meta, len, len);
 +      dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
 +      dma_unmap_len_set(out_meta, len, len);
        /* Add buffer containing Tx command and MAC(!) header to TFD's
         * first entry */
        priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
  
        if (!ieee80211_has_morefrags(hdr->frame_control)) {
                txq->need_update = 1;
 -              if (qc)
 -                      priv->stations[sta_id].tid[tid].seq_number = seq_number;
        } else {
                wait_write_ptr = 1;
                txq->need_update = 0;
@@@ -1018,8 -1009,6 +1018,8 @@@ int iwlagn_tx_agg_start(struct iwl_pri
        if (ret)
                return ret;
  
 +      spin_lock_irqsave(&priv->sta_lock, flags);
 +      tid_data = &priv->stations[sta_id].tid[tid];
        if (tid_data->tfds_in_queue == 0) {
                IWL_DEBUG_HT(priv, "HW queue is empty\n");
                tid_data->agg.state = IWL_AGG_ON;
                             tid_data->tfds_in_queue);
                tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
        }
 +      spin_unlock_irqrestore(&priv->sta_lock, flags);
        return ret;
  }
  
@@@ -1052,14 -1040,11 +1052,14 @@@ int iwlagn_tx_agg_stop(struct iwl_priv 
                return -ENXIO;
        }
  
 +      spin_lock_irqsave(&priv->sta_lock, flags);
 +
        if (priv->stations[sta_id].tid[tid].agg.state ==
                                IWL_EMPTYING_HW_QUEUE_ADDBA) {
                IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
                ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
 +              spin_unlock_irqrestore(&priv->sta_lock, flags);
                return 0;
        }
  
                IWL_DEBUG_HT(priv, "Stopping a non empty AGG HW QUEUE\n");
                priv->stations[sta_id].tid[tid].agg.state =
                                IWL_EMPTYING_HW_QUEUE_DELBA;
 +              spin_unlock_irqrestore(&priv->sta_lock, flags);
                return 0;
        }
  
        IWL_DEBUG_HT(priv, "HW queue is empty\n");
        priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
  
 -      spin_lock_irqsave(&priv->lock, flags);
 +      /* do not restore/save irqs */
 +      spin_unlock(&priv->sta_lock);
 +      spin_lock(&priv->lock);
 +
        /*
         * the only reason this call can fail is queue number out of range,
         * which can happen if uCode is reloaded and all the station
@@@ -1111,8 -1092,6 +1111,8 @@@ int iwlagn_txq_check_empty(struct iwl_p
        u8 *addr = priv->stations[sta_id].sta.sta.addr;
        struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
  
 +      WARN_ON(!spin_is_locked(&priv->sta_lock));
 +
        switch (priv->stations[sta_id].tid[tid].agg.state) {
        case IWL_EMPTYING_HW_QUEUE_DELBA:
                /* We are reclaiming the last packet of the */
                }
                break;
        }
 +
        return 0;
  }
  
@@@ -1147,6 -1125,7 +1147,7 @@@ static void iwlagn_tx_status(struct iwl
        struct ieee80211_sta *sta;
        struct iwl_station_priv *sta_priv;
  
+       rcu_read_lock();
        sta = ieee80211_find_sta(priv->vif, hdr->addr1);
        if (sta) {
                sta_priv = (void *)sta->drv_priv;
                    atomic_dec_return(&sta_priv->pending_frames) == 0)
                        ieee80211_sta_block_awake(priv->hw, sta, false);
        }
+       rcu_read_unlock();
  
        ieee80211_tx_status_irqsafe(priv->hw, skb);
  }
@@@ -1179,12 -1159,12 +1181,12 @@@ int iwlagn_tx_queue_reclaim(struct iwl_
             q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
  
                tx_info = &txq->txb[txq->q.read_ptr];
 -              iwlagn_tx_status(priv, tx_info->skb[0]);
 +              iwlagn_tx_status(priv, tx_info->skb);
  
 -              hdr = (struct ieee80211_hdr *)tx_info->skb[0]->data;
 +              hdr = (struct ieee80211_hdr *)tx_info->skb->data;
                if (hdr && ieee80211_is_data_qos(hdr->frame_control))
                        nfreed++;
 -              tx_info->skb[0] = NULL;
 +              tx_info->skb = NULL;
  
                if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
                        priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
@@@ -1208,7 -1188,7 +1210,7 @@@ static int iwlagn_tx_status_reply_compr
        int i, sh, ack;
        u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
        u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
 -      u64 bitmap;
 +      u64 bitmap, sent_bitmap;
        int successes = 0;
        struct ieee80211_tx_info *info;
  
  
        /* check for success or failure according to the
         * transmitted bitmap and block-ack bitmap */
 -      bitmap &= agg->bitmap;
 +      sent_bitmap = bitmap & agg->bitmap;
  
        /* For each frame attempted in aggregation,
         * update driver's record of tx frame's status. */
 -      for (i = 0; i < agg->frame_count ; i++) {
 -              ack = bitmap & (1ULL << i);
 -              successes += !!ack;
 +      i = 0;
 +      while (sent_bitmap) {
 +              ack = sent_bitmap & 1ULL;
 +              successes += ack;
                IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n",
                        ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff,
                        agg->start_idx + i);
 +              sent_bitmap >>= 1;
 +              ++i;
        }
  
 -      info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]);
 +      info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb);
        memset(&info->status, 0, sizeof(info->status));
        info->flags |= IEEE80211_TX_STAT_ACK;
        info->flags |= IEEE80211_TX_STAT_AMPDU;
        info->status.ampdu_ack_len = successes;
 -      info->status.ampdu_ack_map = bitmap;
        info->status.ampdu_len = agg->frame_count;
        iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
  
@@@ -1303,7 -1281,6 +1305,7 @@@ void iwlagn_rx_reply_compressed_ba(stru
        int index;
        int sta_id;
        int tid;
 +      unsigned long flags;
  
        /* "flow" corresponds to Tx queue */
        u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
        sta_id = ba_resp->sta_id;
        tid = ba_resp->tid;
        agg = &priv->stations[sta_id].tid[tid].agg;
+       if (unlikely(agg->txq_id != scd_flow)) {
+               IWL_ERR(priv, "BA scd_flow %d does not match txq_id %d\n",
+                       scd_flow, agg->txq_id);
+               return;
+       }
  
        /* Find index just before block-ack window */
        index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
  
 -      /* TODO: Need to get this copy more safely - now good for debug */
 +      spin_lock_irqsave(&priv->sta_lock, flags);
  
        IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
                           "sta_id = %d\n",
  
                iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow);
        }
 +
 +      spin_unlock_irqrestore(&priv->sta_lock, flags);
  }
index 4ade9a68278a435b611df46b288a25a7f3257749,24aff654fa9c44251b11f3d12ab63d639ea06384..d857f8496f695e75a480aae910411418c1fe1a32
@@@ -120,7 -120,7 +120,7 @@@ int iwl_commit_rxon(struct iwl_priv *pr
            (priv->switch_rxon.channel != priv->staging_rxon.channel)) {
                IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
                      le16_to_cpu(priv->switch_rxon.channel));
 -              priv->switch_rxon.switch_in_progress = false;
 +              iwl_chswitch_done(priv, false);
        }
  
        /* If we don't need to send a full RXON, we can use
@@@ -367,8 -367,7 +367,8 @@@ static unsigned int iwl_hw_get_beacon_c
  
        /* Set up packet rate and flags */
        rate = iwl_rate_get_lowest_plcp(priv);
 -      priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
 +      priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
 +                                            priv->hw_params.valid_tx_ant);
        rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
        if ((rate >= IWL_FIRST_CCK_RATE) && (rate <= IWL_LAST_CCK_RATE))
                rate_flags |= RATE_MCS_CCK_MSK;
@@@ -475,25 -474,18 +475,25 @@@ void iwl_hw_txq_free_tfd(struct iwl_pri
        /* Unmap tx_cmd */
        if (num_tbs)
                pci_unmap_single(dev,
 -                              pci_unmap_addr(&txq->meta[index], mapping),
 -                              pci_unmap_len(&txq->meta[index], len),
 +                              dma_unmap_addr(&txq->meta[index], mapping),
 +                              dma_unmap_len(&txq->meta[index], len),
                                PCI_DMA_BIDIRECTIONAL);
  
        /* Unmap chunks, if any. */
 -      for (i = 1; i < num_tbs; i++) {
 +      for (i = 1; i < num_tbs; i++)
                pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i),
                                iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE);
  
 -              if (txq->txb) {
 -                      dev_kfree_skb(txq->txb[txq->q.read_ptr].skb[i - 1]);
 -                      txq->txb[txq->q.read_ptr].skb[i - 1] = NULL;
 +      /* free SKB */
 +      if (txq->txb) {
 +              struct sk_buff *skb;
 +
 +              skb = txq->txb[txq->q.read_ptr].skb;
 +
 +              /* can be called from irqs-disabled context */
 +              if (skb) {
 +                      dev_kfree_skb_any(skb);
 +                      txq->txb[txq->q.read_ptr].skb = NULL;
                }
        }
  }
@@@ -941,8 -933,6 +941,8 @@@ void iwl_rx_handle(struct iwl_priv *pri
                fill_rx = 1;
  
        while (i != r) {
 +              int len;
 +
                rxb = rxq->queue[i];
  
                /* If an RXB doesn't have a Rx queue slot associated with it,
                               PCI_DMA_FROMDEVICE);
                pkt = rxb_addr(rxb);
  
 -              trace_iwlwifi_dev_rx(priv, pkt,
 -                      le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
 +              len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
 +              len += sizeof(u32); /* account for status word */
 +              trace_iwlwifi_dev_rx(priv, pkt, len);
  
                /* Reclaim a command buffer only if this packet is a response
                 *   to a (driver-originated) command.
@@@ -1477,12 -1466,7 +1477,12 @@@ bool iwl_good_ack_health(struct iwl_pri
                                " expected_ack_cnt = %d\n",
                                actual_ack_cnt_delta, expected_ack_cnt_delta);
  
 -#ifdef CONFIG_IWLWIFI_DEBUG
 +#ifdef CONFIG_IWLWIFI_DEBUGFS
 +              /*
 +               * This is ifdef'ed on DEBUGFS because otherwise the
 +               * statistics aren't available. If DEBUGFS is set but
 +               * DEBUG is not, these will just compile out.
 +               */
                IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n",
                                priv->delta_statistics.tx.rx_detected_cnt);
                IWL_DEBUG_RADIO(priv,
@@@ -1710,9 -1694,6 +1710,9 @@@ struct iwlagn_firmware_pieces 
        size_t inst_size, data_size, init_size, init_data_size, boot_size;
  
        u32 build;
 +
 +      u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
 +      u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
  };
  
  static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
@@@ -1890,42 -1871,6 +1890,42 @@@ static int iwlagn_load_firmware(struct 
                        capa->max_probe_length =
                                le32_to_cpup((__le32 *)tlv_data);
                        break;
 +              case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
 +                      if (tlv_len != 4)
 +                              return -EINVAL;
 +                      pieces->init_evtlog_ptr =
 +                              le32_to_cpup((__le32 *)tlv_data);
 +                      break;
 +              case IWL_UCODE_TLV_INIT_EVTLOG_SIZE:
 +                      if (tlv_len != 4)
 +                              return -EINVAL;
 +                      pieces->init_evtlog_size =
 +                              le32_to_cpup((__le32 *)tlv_data);
 +                      break;
 +              case IWL_UCODE_TLV_INIT_ERRLOG_PTR:
 +                      if (tlv_len != 4)
 +                              return -EINVAL;
 +                      pieces->init_errlog_ptr =
 +                              le32_to_cpup((__le32 *)tlv_data);
 +                      break;
 +              case IWL_UCODE_TLV_RUNT_EVTLOG_PTR:
 +                      if (tlv_len != 4)
 +                              return -EINVAL;
 +                      pieces->inst_evtlog_ptr =
 +                              le32_to_cpup((__le32 *)tlv_data);
 +                      break;
 +              case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE:
 +                      if (tlv_len != 4)
 +                              return -EINVAL;
 +                      pieces->inst_evtlog_size =
 +                              le32_to_cpup((__le32 *)tlv_data);
 +                      break;
 +              case IWL_UCODE_TLV_RUNT_ERRLOG_PTR:
 +                      if (tlv_len != 4)
 +                              return -EINVAL;
 +                      pieces->inst_errlog_ptr =
 +                              le32_to_cpup((__le32 *)tlv_data);
 +                      break;
                default:
                        break;
                }
@@@ -2118,26 -2063,6 +2118,26 @@@ static void iwl_ucode_callback(const st
                        goto err_pci_alloc;
        }
  
 +      /* Now that we can no longer fail, copy information */
 +
 +      /*
 +       * The (size - 16) / 12 formula is based on the information recorded
 +       * for each event, which is of mode 1 (including timestamp) for all
 +       * new microcodes that include this information.
 +       */
 +      priv->_agn.init_evtlog_ptr = pieces.init_evtlog_ptr;
 +      if (pieces.init_evtlog_size)
 +              priv->_agn.init_evtlog_size = (pieces.init_evtlog_size - 16)/12;
 +      else
 +              priv->_agn.init_evtlog_size = priv->cfg->max_event_log_size;
 +      priv->_agn.init_errlog_ptr = pieces.init_errlog_ptr;
 +      priv->_agn.inst_evtlog_ptr = pieces.inst_evtlog_ptr;
 +      if (pieces.inst_evtlog_size)
 +              priv->_agn.inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12;
 +      else
 +              priv->_agn.inst_evtlog_size = priv->cfg->max_event_log_size;
 +      priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr;
 +
        /* Copy images into buffers for card's bus-master reads ... */
  
        /* Runtime instructions (first block of data in file) */
@@@ -2270,15 -2195,10 +2270,15 @@@ void iwl_dump_nic_error_log(struct iwl_
        u32 blink1, blink2, ilink1, ilink2;
        u32 pc, hcmd;
  
 -      if (priv->ucode_type == UCODE_INIT)
 +      if (priv->ucode_type == UCODE_INIT) {
                base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
 -      else
 +              if (!base)
 +                      base = priv->_agn.init_errlog_ptr;
 +      } else {
                base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
 +              if (!base)
 +                      base = priv->_agn.inst_errlog_ptr;
 +      }
  
        if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
                IWL_ERR(priv,
@@@ -2338,16 -2258,10 +2338,16 @@@ static int iwl_print_event_log(struct i
  
        if (num_events == 0)
                return pos;
 -      if (priv->ucode_type == UCODE_INIT)
 +
 +      if (priv->ucode_type == UCODE_INIT) {
                base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
 -      else
 +              if (!base)
 +                      base = priv->_agn.init_evtlog_ptr;
 +      } else {
                base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
 +              if (!base)
 +                      base = priv->_agn.inst_evtlog_ptr;
 +      }
  
        if (mode == 0)
                event_size = 2 * sizeof(u32);
@@@ -2449,21 -2363,13 +2449,21 @@@ int iwl_dump_nic_event_log(struct iwl_p
        u32 num_wraps;  /* # times uCode wrapped to top of log */
        u32 next_entry; /* index of next entry to be written by uCode */
        u32 size;       /* # entries that we'll print */
 +      u32 logsize;
        int pos = 0;
        size_t bufsz = 0;
  
 -      if (priv->ucode_type == UCODE_INIT)
 +      if (priv->ucode_type == UCODE_INIT) {
                base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
 -      else
 +              logsize = priv->_agn.init_evtlog_size;
 +              if (!base)
 +                      base = priv->_agn.init_evtlog_ptr;
 +      } else {
                base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
 +              logsize = priv->_agn.inst_evtlog_size;
 +              if (!base)
 +                      base = priv->_agn.inst_evtlog_ptr;
 +      }
  
        if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
                IWL_ERR(priv,
        num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
        next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
  
 -      if (capacity > priv->cfg->max_event_log_size) {
 +      if (capacity > logsize) {
                IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
 -                      capacity, priv->cfg->max_event_log_size);
 -              capacity = priv->cfg->max_event_log_size;
 +                      capacity, logsize);
 +              capacity = logsize;
        }
  
 -      if (next_entry > priv->cfg->max_event_log_size) {
 +      if (next_entry > logsize) {
                IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
 -                      next_entry, priv->cfg->max_event_log_size);
 -              next_entry = priv->cfg->max_event_log_size;
 +                      next_entry, logsize);
 +              next_entry = logsize;
        }
  
        size = num_wraps ? capacity : next_entry;
@@@ -2612,6 -2518,8 +2612,6 @@@ static void iwl_alive_start(struct iwl_
  
                if (priv->cfg->ops->hcmd->set_rxon_chain)
                        priv->cfg->ops->hcmd->set_rxon_chain(priv);
 -
 -              memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
        }
  
        /* Configure Bluetooth device coexistence support */
@@@ -3026,16 -2934,20 +3026,16 @@@ void iwl_post_associate(struct iwl_pri
        IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
                        vif->bss_conf.aid, vif->bss_conf.beacon_int);
  
 -      if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
 +      if (vif->bss_conf.use_short_preamble)
                priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
        else
                priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
  
        if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
 -              if (vif->bss_conf.assoc_capability &
 -                                      WLAN_CAPABILITY_SHORT_SLOT_TIME)
 +              if (vif->bss_conf.use_short_slot)
                        priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
                        priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 -
 -              if (vif->type == NL80211_IFTYPE_ADHOC)
 -                      priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
        }
  
        iwlcore_commit_rxon(priv);
@@@ -3261,7 -3173,8 +3261,7 @@@ void iwl_config_ap(struct iwl_priv *pri
  
                priv->staging_rxon.assoc_id = 0;
  
 -              if (vif->bss_conf.assoc_capability &
 -                                              WLAN_CAPABILITY_SHORT_PREAMBLE)
 +              if (vif->bss_conf.use_short_preamble)
                        priv->staging_rxon.flags |=
                                RXON_FLG_SHORT_PREAMBLE_MSK;
                else
                                ~RXON_FLG_SHORT_PREAMBLE_MSK;
  
                if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
 -                      if (vif->bss_conf.assoc_capability &
 -                                              WLAN_CAPABILITY_SHORT_SLOT_TIME)
 +                      if (vif->bss_conf.use_short_slot)
                                priv->staging_rxon.flags |=
                                        RXON_FLG_SHORT_SLOT_MSK;
                        else
                                priv->staging_rxon.flags &=
                                        ~RXON_FLG_SHORT_SLOT_MSK;
 -
 -                      if (vif->type == NL80211_IFTYPE_ADHOC)
 -                              priv->staging_rxon.flags &=
 -                                      ~RXON_FLG_SHORT_SLOT_MSK;
                }
                /* restore RXON assoc */
                priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
@@@ -3320,9 -3238,17 +3320,9 @@@ static int iwl_mac_set_key(struct ieee8
                return -EOPNOTSUPP;
        }
  
 -      if (sta) {
 -              sta_id = iwl_sta_id(sta);
 -
 -              if (sta_id == IWL_INVALID_STATION) {
 -                      IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
 -                                         sta->addr);
 -                      return -EINVAL;
 -              }
 -      } else {
 -              sta_id = priv->hw_params.bcast_sta_id;
 -      }
 +      sta_id = iwl_sta_id_or_broadcast(priv, sta);
 +      if (sta_id == IWL_INVALID_STATION)
 +              return -EINVAL;
  
        mutex_lock(&priv->mutex);
        iwl_scan_cancel_timeout(priv, 100);
@@@ -3465,10 -3391,12 +3465,12 @@@ static int iwlagn_mac_sta_add(struct ie
        int ret;
        u8 sta_id;
  
-       sta_priv->common.sta_id = IWL_INVALID_STATION;
        IWL_DEBUG_INFO(priv, "received request to add station %pM\n",
                        sta->addr);
+       mutex_lock(&priv->mutex);
+       IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n",
+                       sta->addr);
+       sta_priv->common.sta_id = IWL_INVALID_STATION;
  
        atomic_set(&sta_priv->pending_frames, 0);
        if (vif->type == NL80211_IFTYPE_AP)
                IWL_ERR(priv, "Unable to add station %pM (%d)\n",
                        sta->addr, ret);
                /* Should we return success if return code is EEXIST ? */
+               mutex_unlock(&priv->mutex);
                return ret;
        }
  
        IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
                       sta->addr);
        iwl_rs_rate_init(priv, sta, sta_id);
+       mutex_unlock(&priv->mutex);
  
        return 0;
  }
  
 +static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
 +                                 struct ieee80211_channel_switch *ch_switch)
 +{
 +      struct iwl_priv *priv = hw->priv;
 +      const struct iwl_channel_info *ch_info;
 +      struct ieee80211_conf *conf = &hw->conf;
 +      struct iwl_ht_config *ht_conf = &priv->current_ht_config;
 +      u16 ch;
 +      unsigned long flags = 0;
 +
 +      IWL_DEBUG_MAC80211(priv, "enter\n");
 +
 +      if (iwl_is_rfkill(priv))
 +              goto out_exit;
 +
 +      if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
 +          test_bit(STATUS_SCANNING, &priv->status))
 +              goto out_exit;
 +
 +      if (!iwl_is_associated(priv))
 +              goto out_exit;
 +
 +      /* channel switch in progress */
 +      if (priv->switch_rxon.switch_in_progress == true)
 +              goto out_exit;
 +
 +      mutex_lock(&priv->mutex);
 +      if (priv->cfg->ops->lib->set_channel_switch) {
 +
 +              ch = ieee80211_frequency_to_channel(
 +                      ch_switch->channel->center_freq);
 +              if (le16_to_cpu(priv->active_rxon.channel) != ch) {
 +                      ch_info = iwl_get_channel_info(priv,
 +                                                     conf->channel->band,
 +                                                     ch);
 +                      if (!is_channel_valid(ch_info)) {
 +                              IWL_DEBUG_MAC80211(priv, "invalid channel\n");
 +                              goto out;
 +                      }
 +                      spin_lock_irqsave(&priv->lock, flags);
 +
 +                      priv->current_ht_config.smps = conf->smps_mode;
 +
 +                      /* Configure HT40 channels */
 +                      ht_conf->is_ht = conf_is_ht(conf);
 +                      if (ht_conf->is_ht) {
 +                              if (conf_is_ht40_minus(conf)) {
 +                                      ht_conf->extension_chan_offset =
 +                                              IEEE80211_HT_PARAM_CHA_SEC_BELOW;
 +                                      ht_conf->is_40mhz = true;
 +                              } else if (conf_is_ht40_plus(conf)) {
 +                                      ht_conf->extension_chan_offset =
 +                                              IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
 +                                      ht_conf->is_40mhz = true;
 +                              } else {
 +                                      ht_conf->extension_chan_offset =
 +                                              IEEE80211_HT_PARAM_CHA_SEC_NONE;
 +                                      ht_conf->is_40mhz = false;
 +                              }
 +                      } else
 +                              ht_conf->is_40mhz = false;
 +
 +                      /* if we are switching from ht to 2.4 clear flags
 +                       * from any ht related info since 2.4 does not
 +                       * support ht */
 +                      if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
 +                              priv->staging_rxon.flags = 0;
 +
 +                      iwl_set_rxon_channel(priv, conf->channel);
 +                      iwl_set_rxon_ht(priv, ht_conf);
 +                      iwl_set_flags_for_band(priv, conf->channel->band,
 +                                             priv->vif);
 +                      spin_unlock_irqrestore(&priv->lock, flags);
 +
 +                      iwl_set_rate(priv);
 +                      /*
 +                       * at this point, staging_rxon has the
 +                       * configuration for channel switch
 +                       */
 +                      if (priv->cfg->ops->lib->set_channel_switch(priv,
 +                                                                  ch_switch))
 +                              priv->switch_rxon.switch_in_progress = false;
 +              }
 +      }
 +out:
 +      mutex_unlock(&priv->mutex);
 +out_exit:
 +      if (!priv->switch_rxon.switch_in_progress)
 +              ieee80211_chswitch_done(priv->vif, false);
 +      IWL_DEBUG_MAC80211(priv, "leave\n");
 +}
 +
  /*****************************************************************************
   *
   * driver setup and teardown
@@@ -3641,7 -3479,6 +3645,7 @@@ static void iwl_cancel_deferred_work(st
        cancel_delayed_work(&priv->scan_check);
        cancel_work_sync(&priv->start_internal_scan);
        cancel_delayed_work(&priv->alive_start);
 +      cancel_work_sync(&priv->run_time_calib_work);
        cancel_work_sync(&priv->beacon_update);
        del_timer_sync(&priv->statistics_periodic);
        del_timer_sync(&priv->ucode_trace);
@@@ -3757,7 -3594,6 +3761,7 @@@ static struct ieee80211_ops iwl_hw_ops 
        .sta_notify = iwl_mac_sta_notify,
        .sta_add = iwlagn_mac_sta_add,
        .sta_remove = iwl_mac_sta_remove,
 +      .channel_switch = iwl_mac_channel_switch,
  };
  
  static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
        unsigned long flags;
        u16 pci_cmd;
 +      u8 perm_addr[ETH_ALEN];
  
        /************************
         * 1. Allocating HW data
        priv->pci_dev = pdev;
        priv->inta_mask = CSR_INI_SET_MASK;
  
 -#ifdef CONFIG_IWLWIFI_DEBUG
 -      atomic_set(&priv->restrict_refcnt, 0);
 -#endif
        if (iwl_alloc_traffic_mem(priv))
                IWL_ERR(priv, "Not enough memory to generate traffic log\n");
  
                goto out_free_eeprom;
  
        /* extract MAC Address */
 -      iwl_eeprom_get_mac(priv, priv->mac_addr);
 -      IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->mac_addr);
 -      SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
 +      iwl_eeprom_get_mac(priv, perm_addr);
 +      IWL_DEBUG_INFO(priv, "MAC address: %pM\n", perm_addr);
 +      SET_IEEE80211_PERM_ADDR(priv->hw, perm_addr);
  
        /************************
         * 5. Setup HW constants
@@@ -4155,47 -3993,6 +4159,47 @@@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_c
        {IWL_PCI_DEVICE(0x0082, 0x1201, iwl6000g2a_2agn_cfg)},
        {IWL_PCI_DEVICE(0x0085, 0x1211, iwl6000g2a_2agn_cfg)},
        {IWL_PCI_DEVICE(0x0082, 0x1221, iwl6000g2a_2agn_cfg)},
 +      {IWL_PCI_DEVICE(0x0082, 0x1206, iwl6000g2a_2abg_cfg)},
 +      {IWL_PCI_DEVICE(0x0085, 0x1216, iwl6000g2a_2abg_cfg)},
 +      {IWL_PCI_DEVICE(0x0082, 0x1226, iwl6000g2a_2abg_cfg)},
 +      {IWL_PCI_DEVICE(0x0082, 0x1207, iwl6000g2a_2bg_cfg)},
 +      {IWL_PCI_DEVICE(0x0082, 0x1301, iwl6000g2a_2agn_cfg)},
 +      {IWL_PCI_DEVICE(0x0082, 0x1306, iwl6000g2a_2abg_cfg)},
 +      {IWL_PCI_DEVICE(0x0082, 0x1307, iwl6000g2a_2bg_cfg)},
 +      {IWL_PCI_DEVICE(0x0082, 0x1321, iwl6000g2a_2agn_cfg)},
 +      {IWL_PCI_DEVICE(0x0082, 0x1326, iwl6000g2a_2abg_cfg)},
 +      {IWL_PCI_DEVICE(0x0085, 0x1311, iwl6000g2a_2agn_cfg)},
 +      {IWL_PCI_DEVICE(0x0085, 0x1316, iwl6000g2a_2abg_cfg)},
 +
 +/* 6x00 Series Gen2b */
 +      {IWL_PCI_DEVICE(0x008F, 0x5105, iwl6000g2b_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x0090, 0x5115, iwl6000g2b_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x008F, 0x5125, iwl6000g2b_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x008F, 0x5107, iwl6000g2b_bg_cfg)},
 +      {IWL_PCI_DEVICE(0x008F, 0x5201, iwl6000g2b_2agn_cfg)},
 +      {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6000g2b_2agn_cfg)},
 +      {IWL_PCI_DEVICE(0x008F, 0x5221, iwl6000g2b_2agn_cfg)},
 +      {IWL_PCI_DEVICE(0x008F, 0x5206, iwl6000g2b_2abg_cfg)},
 +      {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6000g2b_2abg_cfg)},
 +      {IWL_PCI_DEVICE(0x008F, 0x5226, iwl6000g2b_2abg_cfg)},
 +      {IWL_PCI_DEVICE(0x008F, 0x5207, iwl6000g2b_2bg_cfg)},
 +      {IWL_PCI_DEVICE(0x008A, 0x5301, iwl6000g2b_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x008A, 0x5305, iwl6000g2b_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x008A, 0x5307, iwl6000g2b_bg_cfg)},
 +      {IWL_PCI_DEVICE(0x008A, 0x5321, iwl6000g2b_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x008A, 0x5325, iwl6000g2b_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x008B, 0x5311, iwl6000g2b_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x008B, 0x5315, iwl6000g2b_bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6000g2b_2agn_cfg)},
 +      {IWL_PCI_DEVICE(0x0090, 0x5215, iwl6000g2b_2bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6000g2b_2abg_cfg)},
 +      {IWL_PCI_DEVICE(0x0091, 0x5201, iwl6000g2b_2agn_cfg)},
 +      {IWL_PCI_DEVICE(0x0091, 0x5205, iwl6000g2b_2bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x0091, 0x5206, iwl6000g2b_2abg_cfg)},
 +      {IWL_PCI_DEVICE(0x0091, 0x5207, iwl6000g2b_2bg_cfg)},
 +      {IWL_PCI_DEVICE(0x0091, 0x5221, iwl6000g2b_2agn_cfg)},
 +      {IWL_PCI_DEVICE(0x0091, 0x5225, iwl6000g2b_2bgn_cfg)},
 +      {IWL_PCI_DEVICE(0x0091, 0x5226, iwl6000g2b_2abg_cfg)},
  
  /* 6x50 WiFi/WiMax Series */
        {IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
index b8bcd48eb8fa2081a59fe5cf3bd0902c642b56e1,386c5f96eff81c6467f026bc970c39734b853ffb..798f93e0ff5028f2bbe2b440c82af2f139a76b06
@@@ -333,8 -333,7 +333,8 @@@ int iwl_mac_hw_scan(struct ieee80211_h
                goto out_unlock;
        }
  
 -      if (test_bit(STATUS_SCANNING, &priv->status)) {
 +      if (test_bit(STATUS_SCANNING, &priv->status) &&
 +          !priv->is_internal_short_scan) {
                IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
                ret = -EAGAIN;
                goto out_unlock;
        /* mac80211 will only ask for one band at a time */
        priv->scan_band = req->channels[0]->band;
        priv->scan_request = req;
 +      priv->scan_vif = vif;
  
 -      ret = iwl_scan_initiate(priv, vif);
 +      /*
 +       * If an internal scan is in progress, just set
 +       * up the scan_request as per above.
 +       */
 +      if (priv->is_internal_short_scan)
 +              ret = 0;
 +      else
 +              ret = iwl_scan_initiate(priv, vif);
  
        IWL_DEBUG_MAC80211(priv, "leave\n");
  
@@@ -447,7 -438,7 +447,7 @@@ EXPORT_SYMBOL(iwl_bg_scan_check)
   */
  
  u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
 -                     const u8 *ies, int ie_len, int left)
 +                     const u8 *ta, const u8 *ies, int ie_len, int left)
  {
        int len = 0;
        u8 *pos = NULL;
  
        frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
        memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
 -      memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
 +      memcpy(frame->sa, ta, ETH_ALEN);
        memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
        frame->seq_ctrl = 0;
  
@@@ -500,6 -491,7 +500,7 @@@ void iwl_bg_abort_scan(struct work_stru
  
        mutex_lock(&priv->mutex);
  
+       cancel_delayed_work_sync(&priv->scan_check);
        set_bit(STATUS_SCAN_ABORTING, &priv->status);
        iwl_send_scan_abort(priv);
  
@@@ -522,21 -514,7 +523,21 @@@ void iwl_bg_scan_completed(struct work_
                priv->is_internal_short_scan = false;
                IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
                internal = true;
 +      } else {
 +              priv->scan_request = NULL;
 +              priv->scan_vif = NULL;
        }
 +
 +      if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 +              goto out;
 +
 +      if (internal && priv->scan_request)
 +              iwl_scan_initiate(priv, priv->scan_vif);
 +
 +      /* Since setting the TXPOWER may have been deferred while
 +       * performing the scan, fire one off */
 +      iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
 + out:
        mutex_unlock(&priv->mutex);
  
        /*
         */
        if (!internal)
                ieee80211_scan_completed(priv->hw, false);
 -
 -      if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 -              return;
 -
 -      /* Since setting the TXPOWER may have been deferred while
 -       * performing the scan, fire one off */
 -      mutex_lock(&priv->mutex);
 -      iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
 -      mutex_unlock(&priv->mutex);
  }
  EXPORT_SYMBOL(iwl_bg_scan_completed);
  
index c7127132c29843a2851f34738ac901909633d73f,c27c13fbb1aec26bac302623b96d089e1f13c0dd..d57df6c02db307110a25e4f968d3107bc7d241b6
@@@ -311,10 -311,10 +311,10 @@@ int iwl_add_station_common(struct iwl_p
                                  struct ieee80211_sta_ht_cap *ht_info,
                                  u8 *sta_id_r)
  {
 -      struct iwl_station_entry *station;
        unsigned long flags_spin;
        int ret = 0;
        u8 sta_id;
 +      struct iwl_addsta_cmd sta_cmd;
  
        *sta_id_r = 0;
        spin_lock_irqsave(&priv->sta_lock, flags_spin);
        }
  
        priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS;
 -      station = &priv->stations[sta_id];
 +      memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
        spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
  
        /* Add station to device's station table */
 -      ret = iwl_send_add_sta(priv, &station->sta, CMD_SYNC);
 +      ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
        if (ret) {
 -              IWL_ERR(priv, "Adding station %pM failed.\n", station->sta.sta.addr);
                spin_lock_irqsave(&priv->sta_lock, flags_spin);
 +              IWL_ERR(priv, "Adding station %pM failed.\n",
 +                      priv->stations[sta_id].sta.sta.addr);
                priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
                priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
                spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
@@@ -489,7 -488,7 +489,7 @@@ static void iwl_sta_ucode_deactivate(st
  }
  
  static int iwl_send_remove_station(struct iwl_priv *priv,
 -                                 struct iwl_station_entry *station)
 +                                 const u8 *addr, int sta_id)
  {
        struct iwl_rx_packet *pkt;
        int ret;
  
        memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
        rm_sta_cmd.num_sta = 1;
 -      memcpy(&rm_sta_cmd.addr, &station->sta.sta.addr , ETH_ALEN);
 +      memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN);
  
        cmd.flags |= CMD_WANT_SKB;
  
                switch (pkt->u.rem_sta.status) {
                case REM_STA_SUCCESS_MSK:
                        spin_lock_irqsave(&priv->sta_lock, flags_spin);
 -                      iwl_sta_ucode_deactivate(priv, station->sta.sta.sta_id);
 +                      iwl_sta_ucode_deactivate(priv, sta_id);
                        spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
                        IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
                        break;
  int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
                       const u8 *addr)
  {
 -      struct iwl_station_entry *station;
        unsigned long flags;
  
        if (!iwl_is_ready(priv)) {
  
        BUG_ON(priv->num_stations < 0);
  
 -      station = &priv->stations[sta_id];
        spin_unlock_irqrestore(&priv->sta_lock, flags);
  
 -      return iwl_send_remove_station(priv, station);
 +      return iwl_send_remove_station(priv, addr, sta_id);
  out_err:
        spin_unlock_irqrestore(&priv->sta_lock, flags);
        return -EINVAL;
@@@ -642,13 -643,11 +642,13 @@@ EXPORT_SYMBOL(iwl_clear_ucode_stations)
   */
  void iwl_restore_stations(struct iwl_priv *priv)
  {
 -      struct iwl_station_entry *station;
 +      struct iwl_addsta_cmd sta_cmd;
 +      struct iwl_link_quality_cmd lq;
        unsigned long flags_spin;
        int i;
        bool found = false;
        int ret;
 +      bool send_lq;
  
        if (!iwl_is_ready(priv)) {
                IWL_DEBUG_INFO(priv, "Not ready yet, not restoring any stations.\n");
  
        for (i = 0; i < priv->hw_params.max_stations; i++) {
                if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) {
 +                      memcpy(&sta_cmd, &priv->stations[i].sta,
 +                             sizeof(struct iwl_addsta_cmd));
 +                      send_lq = false;
 +                      if (priv->stations[i].lq) {
 +                              memcpy(&lq, priv->stations[i].lq,
 +                                     sizeof(struct iwl_link_quality_cmd));
 +                              send_lq = true;
 +                      }
                        spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
 -                      station = &priv->stations[i];
 -                      ret = iwl_send_add_sta(priv, &priv->stations[i].sta, CMD_SYNC);
 +                      ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
                        if (ret) {
 -                              IWL_ERR(priv, "Adding station %pM failed.\n",
 -                                      station->sta.sta.addr);
                                spin_lock_irqsave(&priv->sta_lock, flags_spin);
 +                              IWL_ERR(priv, "Adding station %pM failed.\n",
 +                                      priv->stations[i].sta.sta.addr);
                                priv->stations[i].used &= ~IWL_STA_DRIVER_ACTIVE;
                                priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
                                spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
                         * Rate scaling has already been initialized, send
                         * current LQ command
                         */
 -                      if (station->lq)
 -                              iwl_send_lq_cmd(priv, station->lq, CMD_SYNC, true);
 +                      if (send_lq)
 +                              iwl_send_lq_cmd(priv, &lq, CMD_SYNC, true);
                        spin_lock_irqsave(&priv->sta_lock, flags_spin);
                        priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
                }
@@@ -980,16 -972,24 +980,16 @@@ void iwl_update_tkip_key(struct iwl_pri
        unsigned long flags;
        int i;
  
 -      if (sta) {
 -              sta_id = iwl_sta_id(sta);
 -
 -              if (sta_id == IWL_INVALID_STATION) {
 -                      IWL_DEBUG_MAC80211(priv, "leave - %pM not initialised.\n",
 -                                         sta->addr);
 -                      return;
 -              }
 -      } else
 -              sta_id = priv->hw_params.bcast_sta_id;
 -
 -
        if (iwl_scan_cancel(priv)) {
                /* cancel scan failed, just live w/ bad key and rely
                   briefly on SW decryption */
                return;
        }
  
 +      sta_id = iwl_sta_id_or_broadcast(priv, sta);
 +      if (sta_id == IWL_INVALID_STATION)
 +              return;
 +
        spin_lock_irqsave(&priv->sta_lock, flags);
  
        priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
@@@ -1277,8 -1277,9 +1277,8 @@@ void iwl_sta_tx_modify_enable_tid(struc
        priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
        priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 -      spin_unlock_irqrestore(&priv->sta_lock, flags);
 -
        iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 +      spin_unlock_irqrestore(&priv->sta_lock, flags);
  }
  EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid);
  
@@@ -1309,7 -1310,7 +1309,7 @@@ int iwl_sta_rx_agg_stop(struct iwl_pri
                        int tid)
  {
        unsigned long flags;
 -      int sta_id;
 +      int sta_id, ret;
  
        sta_id = iwl_sta_id(sta);
        if (sta_id == IWL_INVALID_STATION) {
        priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
        priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 +      ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
        spin_unlock_irqrestore(&priv->sta_lock, flags);
  
 -      return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
 -                                      CMD_ASYNC);
 +      return ret;
 +
  }
  EXPORT_SYMBOL(iwl_sta_rx_agg_stop);
  
@@@ -1340,9 -1340,9 +1340,9 @@@ void iwl_sta_modify_ps_wake(struct iwl_
        priv->stations[sta_id].sta.sta.modify_mask = 0;
        priv->stations[sta_id].sta.sleep_tx_count = 0;
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 +      iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
        spin_unlock_irqrestore(&priv->sta_lock, flags);
  
 -      iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
  }
  EXPORT_SYMBOL(iwl_sta_modify_ps_wake);
  
@@@ -1357,9 -1357,9 +1357,9 @@@ void iwl_sta_modify_sleep_tx_count(stru
                                        STA_MODIFY_SLEEP_TX_COUNT_MSK;
        priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt);
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 +      iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
        spin_unlock_irqrestore(&priv->sta_lock, flags);
  
 -      iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
  }
  EXPORT_SYMBOL(iwl_sta_modify_sleep_tx_count);
  
@@@ -1373,10 -1373,14 +1373,14 @@@ int iwl_mac_sta_remove(struct ieee80211
  
        IWL_DEBUG_INFO(priv, "received request to remove station %pM\n",
                        sta->addr);
+       mutex_lock(&priv->mutex);
+       IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n",
+                       sta->addr);
        ret = iwl_remove_station(priv, sta_common->sta_id, sta->addr);
        if (ret)
                IWL_ERR(priv, "Error removing station %pM\n",
                        sta->addr);
+       mutex_unlock(&priv->mutex);
        return ret;
  }
  EXPORT_SYMBOL(iwl_mac_sta_remove);
index eb71a8c021acfe4adceb5c8b0defc4f635134098,a27872de41061d62cec0af818aa72f88927396da..697fa6caaceb25c81a5e5dfcf39cd424e52fb126
@@@ -197,7 -197,6 +197,7 @@@ static int iwl3945_set_wep_dynamic_key_
  static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
  {
        unsigned long flags;
 +      struct iwl_addsta_cmd sta_cmd;
  
        spin_lock_irqsave(&priv->sta_lock, flags);
        memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
        priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
        priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 +      memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
        spin_unlock_irqrestore(&priv->sta_lock, flags);
  
        IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n");
 -      iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0);
 -      return 0;
 +      return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
  }
  
  static int iwl3945_set_dynamic_key(struct iwl_priv *priv,
@@@ -475,8 -474,10 +475,8 @@@ static int iwl3945_tx_skb(struct iwl_pr
        u8 unicast;
        u8 sta_id;
        u8 tid = 0;
 -      u16 seq_number = 0;
        __le16 fc;
        u8 wait_write_ptr = 0;
 -      u8 *qc = NULL;
        unsigned long flags;
  
        spin_lock_irqsave(&priv->lock, flags);
        hdr_len = ieee80211_hdrlen(fc);
  
        /* Find index into station table for destination station */
 -      if (!info->control.sta)
 -              sta_id = priv->hw_params.bcast_sta_id;
 -      else
 -              sta_id = iwl_sta_id(info->control.sta);
 +      sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
                               hdr->addr1);
        IWL_DEBUG_RATE(priv, "station Id %d\n", sta_id);
  
        if (ieee80211_is_data_qos(fc)) {
 -              qc = ieee80211_get_qos_ctl(hdr);
 +              u8 *qc = ieee80211_get_qos_ctl(hdr);
                tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
                if (unlikely(tid >= MAX_TID_COUNT))
                        goto drop;
 -              seq_number = priv->stations[sta_id].tid[tid].seq_number &
 -                              IEEE80211_SCTL_SEQ;
 -              hdr->seq_ctrl = cpu_to_le16(seq_number) |
 -                      (hdr->seq_ctrl &
 -                              cpu_to_le16(IEEE80211_SCTL_FRAG));
 -              seq_number += 0x10;
        }
  
        /* Descriptor for chosen Tx queue */
  
        /* Set up driver data for this TFD */
        memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
 -      txq->txb[q->write_ptr].skb[0] = skb;
 +      txq->txb[q->write_ptr].skb = skb;
  
        /* Init first empty entry in queue's array of Tx/cmd buffers */
        out_cmd = txq->cmd[idx];
  
        if (!ieee80211_has_morefrags(hdr->frame_control)) {
                txq->need_update = 1;
 -              if (qc)
 -                      priv->stations[sta_id].tid[tid].seq_number = seq_number;
        } else {
                wait_write_ptr = 1;
                txq->need_update = 0;
                                    len, PCI_DMA_TODEVICE);
        /* we do not map meta data ... so we can safely access address to
         * provide to unmap command*/
 -      pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
 -      pci_unmap_len_set(out_meta, len, len);
 +      dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
 +      dma_unmap_len_set(out_meta, len, len);
  
        /* Add buffer containing Tx command and MAC(!) header to TFD's
         * first entry */
@@@ -665,6 -677,55 +665,6 @@@ drop
        return -1;
  }
  
 -#define BEACON_TIME_MASK_LOW  0x00FFFFFF
 -#define BEACON_TIME_MASK_HIGH 0xFF000000
 -#define TIME_UNIT             1024
 -
 -/*
 - * extended beacon time format
 - * time in usec will be changed into a 32-bit value in 8:24 format
 - * the high 1 byte is the beacon counts
 - * the lower 3 bytes is the time in usec within one beacon interval
 - */
 -
 -static u32 iwl3945_usecs_to_beacons(u32 usec, u32 beacon_interval)
 -{
 -      u32 quot;
 -      u32 rem;
 -      u32 interval = beacon_interval * 1024;
 -
 -      if (!interval || !usec)
 -              return 0;
 -
 -      quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
 -      rem = (usec % interval) & BEACON_TIME_MASK_LOW;
 -
 -      return (quot << 24) + rem;
 -}
 -
 -/* base is usually what we get from ucode with each received frame,
 - * the same as HW timer counter counting down
 - */
 -
 -static __le32 iwl3945_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
 -{
 -      u32 base_low = base & BEACON_TIME_MASK_LOW;
 -      u32 addon_low = addon & BEACON_TIME_MASK_LOW;
 -      u32 interval = beacon_interval * TIME_UNIT;
 -      u32 res = (base & BEACON_TIME_MASK_HIGH) +
 -          (addon & BEACON_TIME_MASK_HIGH);
 -
 -      if (base_low > addon_low)
 -              res += base_low - addon_low;
 -      else if (base_low < addon_low) {
 -              res += interval + base_low - addon_low;
 -              res += (1 << 24);
 -      } else
 -              res += (1 << 24);
 -
 -      return cpu_to_le32(res);
 -}
 -
  static int iwl3945_get_measurement(struct iwl_priv *priv,
                               struct ieee80211_measurement_params *params,
                               u8 type)
        int duration = le16_to_cpu(params->duration);
  
        if (iwl_is_associated(priv))
 -              add_time =
 -                  iwl3945_usecs_to_beacons(
 +              add_time = iwl_usecs_to_beacons(priv,
                        le64_to_cpu(params->start_time) - priv->_3945.last_tsf,
                        le16_to_cpu(priv->rxon_timing.beacon_interval));
  
  
        if (iwl_is_associated(priv))
                spectrum.start_time =
 -                  iwl3945_add_beacon_time(priv->_3945.last_beacon_time,
 -                              add_time,
 +                      iwl_add_beacon_time(priv,
 +                              priv->_3945.last_beacon_time, add_time,
                                le16_to_cpu(priv->rxon_timing.beacon_interval));
        else
                spectrum.start_time = 0;
@@@ -1171,7 -1233,7 +1171,7 @@@ static void iwl3945_rx_queue_free(struc
        }
  
        dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
 -                        rxq->dma_addr);
 +                        rxq->bd_dma);
        dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status),
                          rxq->rb_stts, rxq->rb_stts_dma);
        rxq->bd = NULL;
@@@ -1252,8 -1314,6 +1252,8 @@@ static void iwl3945_rx_handle(struct iw
                IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i);
  
        while (i != r) {
 +              int len;
 +
                rxb = rxq->queue[i];
  
                /* If an RXB doesn't have a Rx queue slot associated with it,
                               PCI_DMA_FROMDEVICE);
                pkt = rxb_addr(rxb);
  
 -              trace_iwlwifi_dev_rx(priv, pkt,
 -                      le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
 +              len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
 +              len += sizeof(u32); /* account for status word */
 +              trace_iwlwifi_dev_rx(priv, pkt, len);
  
                /* Reclaim a command buffer only if this packet is a response
                 *   to a (driver-originated) command.
@@@ -2963,16 -3022,14 +2963,16 @@@ void iwl3945_request_scan(struct iwl_pr
                scan->tx_cmd.len = cpu_to_le16(
                        iwl_fill_probe_req(priv,
                                (struct ieee80211_mgmt *)scan->data,
 +                              vif->addr,
                                priv->scan_request->ie,
                                priv->scan_request->ie_len,
                                IWL_MAX_SCAN_SIZE - sizeof(*scan)));
        } else {
 +              /* use bcast addr, will not be transmitted but must be valid */
                scan->tx_cmd.len = cpu_to_le16(
                        iwl_fill_probe_req(priv,
                                (struct ieee80211_mgmt *)scan->data,
 -                              NULL, 0,
 +                              iwl_bcast_addr, NULL, 0,
                                IWL_MAX_SCAN_SIZE - sizeof(*scan)));
        }
        /* select Rx antennas */
@@@ -3101,16 -3158,19 +3101,16 @@@ void iwl3945_post_associate(struct iwl_
        IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
                        vif->bss_conf.aid, vif->bss_conf.beacon_int);
  
 -      if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
 +      if (vif->bss_conf.use_short_preamble)
                priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
        else
                priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
  
        if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
 -              if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
 +              if (vif->bss_conf.use_short_slot)
                        priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
                        priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 -
 -              if (vif->type == NL80211_IFTYPE_ADHOC)
 -                      priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
        }
  
        iwlcore_commit_rxon(priv);
@@@ -3274,7 -3334,8 +3274,7 @@@ void iwl3945_config_ap(struct iwl_priv 
  
                priv->staging_rxon.assoc_id = 0;
  
 -              if (vif->bss_conf.assoc_capability &
 -                                      WLAN_CAPABILITY_SHORT_PREAMBLE)
 +              if (vif->bss_conf.use_short_preamble)
                        priv->staging_rxon.flags |=
                                RXON_FLG_SHORT_PREAMBLE_MSK;
                else
                                ~RXON_FLG_SHORT_PREAMBLE_MSK;
  
                if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
 -                      if (vif->bss_conf.assoc_capability &
 -                                      WLAN_CAPABILITY_SHORT_SLOT_TIME)
 +                      if (vif->bss_conf.use_short_slot)
                                priv->staging_rxon.flags |=
                                        RXON_FLG_SHORT_SLOT_MSK;
                        else
                                priv->staging_rxon.flags &=
                                        ~RXON_FLG_SHORT_SLOT_MSK;
 -
 -                      if (vif->type == NL80211_IFTYPE_ADHOC)
 -                              priv->staging_rxon.flags &=
 -                                      ~RXON_FLG_SHORT_SLOT_MSK;
                }
                /* restore RXON assoc */
                priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
@@@ -3320,9 -3386,17 +3320,9 @@@ static int iwl3945_mac_set_key(struct i
        static_key = !iwl_is_associated(priv);
  
        if (!static_key) {
 -              if (!sta) {
 -                      sta_id = priv->hw_params.bcast_sta_id;
 -              } else {
 -                      sta_id = iwl_sta_id(sta);
 -                      if (sta_id == IWL_INVALID_STATION) {
 -                              IWL_DEBUG_MAC80211(priv,
 -                                                 "leave - %pM not in station map.\n",
 -                                                 sta->addr);
 -                              return -EINVAL;
 -                      }
 -              }
 +              sta_id = iwl_sta_id_or_broadcast(priv, sta);
 +              if (sta_id == IWL_INVALID_STATION)
 +                      return -EINVAL;
        }
  
        mutex_lock(&priv->mutex);
@@@ -3363,10 -3437,13 +3363,13 @@@ static int iwl3945_mac_sta_add(struct i
        bool is_ap = vif->type == NL80211_IFTYPE_STATION;
        u8 sta_id;
  
-       sta_priv->common.sta_id = IWL_INVALID_STATION;
        IWL_DEBUG_INFO(priv, "received request to add station %pM\n",
                        sta->addr);
+       mutex_lock(&priv->mutex);
+       IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n",
+                       sta->addr);
+       sta_priv->common.sta_id = IWL_INVALID_STATION;
  
        ret = iwl_add_station_common(priv, sta->addr, is_ap, &sta->ht_cap,
                                     &sta_id);
                IWL_ERR(priv, "Unable to add station %pM (%d)\n",
                        sta->addr, ret);
                /* Should we return success if return code is EEXIST ? */
+               mutex_unlock(&priv->mutex);
                return ret;
        }
  
        IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
                       sta->addr);
        iwl3945_rs_rate_init(priv, sta, sta_id);
+       mutex_unlock(&priv->mutex);
  
        return 0;
  }
@@@ -3949,6 -4028,9 +3954,6 @@@ static int iwl3945_pci_probe(struct pci
        priv->pci_dev = pdev;
        priv->inta_mask = CSR_INI_SET_MASK;
  
 -#ifdef CONFIG_IWLWIFI_DEBUG
 -      atomic_set(&priv->restrict_refcnt, 0);
 -#endif
        if (iwl_alloc_traffic_mem(priv))
                IWL_ERR(priv, "Not enough memory to generate traffic log\n");
  
        }
        /* MAC Address location in EEPROM same for 3945/4965 */
        eeprom = (struct iwl3945_eeprom *)priv->eeprom;
 -      memcpy(priv->mac_addr, eeprom->mac_address, ETH_ALEN);
 -      IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->mac_addr);
 -      SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
 +      IWL_DEBUG_INFO(priv, "MAC address: %pM\n", eeprom->mac_address);
 +      SET_IEEE80211_PERM_ADDR(priv->hw, eeprom->mac_address);
  
        /***********************
         * 5. Setup HW Constants
diff --combined net/mac80211/mlme.c
index 637b22411d4195523f55c86a0a54bb1d48c5b814,f803f8b72a930dd58b60ae362ea1b7117f1247b2..85c3ca33333eae4eb9277d9a14064a2ed08e7fdd
@@@ -561,19 -561,23 +561,19 @@@ void ieee80211_recalc_ps(struct ieee802
                beaconint_us = ieee80211_tu_to_usec(
                                        found->vif.bss_conf.beacon_int);
  
 -              timeout = local->hw.conf.dynamic_ps_forced_timeout;
 +              timeout = local->dynamic_ps_forced_timeout;
                if (timeout < 0) {
                        /*
 +                       * Go to full PSM if the user configures a very low
 +                       * latency requirement.
                         * The 2 second value is there for compatibility until
                         * the PM_QOS_NETWORK_LATENCY is configured with real
                         * values.
                         */
 -                      if (latency == 2000000000)
 -                              timeout = 100;
 -                      else if (latency <= 50000)
 -                              timeout = 300;
 -                      else if (latency <= 100000)
 -                              timeout = 100;
 -                      else if (latency <= 500000)
 -                              timeout = 50;
 -                      else
 +                      if (latency > 1900000000 && latency != 2000000000)
                                timeout = 0;
 +                      else
 +                              timeout = 100;
                }
                local->hw.conf.dynamic_ps_timeout = timeout;
  
@@@ -802,12 -806,11 +802,12 @@@ static void ieee80211_set_associated(st
  {
        struct ieee80211_bss *bss = (void *)cbss->priv;
        struct ieee80211_local *local = sdata->local;
 +      struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
  
        bss_info_changed |= BSS_CHANGED_ASSOC;
        /* set timing information */
 -      sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
 -      sdata->vif.bss_conf.timestamp = cbss->tsf;
 +      bss_conf->beacon_int = cbss->beacon_interval;
 +      bss_conf->timestamp = cbss->tsf;
  
        bss_info_changed |= BSS_CHANGED_BEACON_INT;
        bss_info_changed |= ieee80211_handle_bss_capability(sdata,
  
        ieee80211_led_assoc(local, 1);
  
 -      sdata->vif.bss_conf.assoc = 1;
 +      bss_conf->assoc = 1;
        /*
         * For now just always ask the driver to update the basic rateset
         * when we have associated, we aren't checking whether it actually
  
        /* Tell the driver to monitor connection quality (if supported) */
        if ((local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) &&
 -          sdata->vif.bss_conf.cqm_rssi_thold)
 +          bss_conf->cqm_rssi_thold)
                bss_info_changed |= BSS_CHANGED_CQM;
  
 +      /* Enable ARP filtering */
 +      if (bss_conf->arp_filter_enabled != sdata->arp_filter_state) {
 +              bss_conf->arp_filter_enabled = sdata->arp_filter_state;
 +              bss_info_changed |= BSS_CHANGED_ARP_FILTER;
 +      }
 +
        ieee80211_bss_info_change_notify(sdata, bss_info_changed);
  
        mutex_lock(&local->iflist_mtx);
@@@ -901,13 -898,13 +901,13 @@@ static void ieee80211_set_disassoc(stru
        netif_tx_stop_all_queues(sdata->dev);
        netif_carrier_off(sdata->dev);
  
 -      rcu_read_lock();
 +      mutex_lock(&local->sta_mtx);
        sta = sta_info_get(sdata, bssid);
        if (sta) {
 -              set_sta_flags(sta, WLAN_STA_DISASSOC);
 +              set_sta_flags(sta, WLAN_STA_BLOCK_BA);
                ieee80211_sta_tear_down_BA_sessions(sta);
        }
 -      rcu_read_unlock();
 +      mutex_unlock(&local->sta_mtx);
  
        changed |= ieee80211_reset_erp_info(sdata);
  
  
        ieee80211_hw_config(local, config_changed);
  
 +      /* Disable ARP filtering */
 +      if (sdata->vif.bss_conf.arp_filter_enabled) {
 +              sdata->vif.bss_conf.arp_filter_enabled = false;
 +              changed |= BSS_CHANGED_ARP_FILTER;
 +      }
 +
        /* The BSSID (not really interesting) and HT changed */
        changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
        ieee80211_bss_info_change_notify(sdata, changed);
@@@ -1642,8 -1633,35 +1642,8 @@@ static void ieee80211_rx_mgmt_beacon(st
        ieee80211_bss_info_change_notify(sdata, changed);
  }
  
 -ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
 -                                        struct sk_buff *skb)
 -{
 -      struct ieee80211_local *local = sdata->local;
 -      struct ieee80211_mgmt *mgmt;
 -      u16 fc;
 -
 -      if (skb->len < 24)
 -              return RX_DROP_MONITOR;
 -
 -      mgmt = (struct ieee80211_mgmt *) skb->data;
 -      fc = le16_to_cpu(mgmt->frame_control);
 -
 -      switch (fc & IEEE80211_FCTL_STYPE) {
 -      case IEEE80211_STYPE_PROBE_RESP:
 -      case IEEE80211_STYPE_BEACON:
 -      case IEEE80211_STYPE_DEAUTH:
 -      case IEEE80211_STYPE_DISASSOC:
 -      case IEEE80211_STYPE_ACTION:
 -              skb_queue_tail(&sdata->u.mgd.skb_queue, skb);
 -              ieee80211_queue_work(&local->hw, &sdata->u.mgd.work);
 -              return RX_QUEUED;
 -      }
 -
 -      return RX_DROP_MONITOR;
 -}
 -
 -static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 -                                       struct sk_buff *skb)
 +void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 +                                struct sk_buff *skb)
  {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_rx_status *rx_status;
                        break;
                case IEEE80211_STYPE_ACTION:
                        switch (mgmt->u.action.category) {
 -                      case WLAN_CATEGORY_BACK: {
 -                              struct ieee80211_local *local = sdata->local;
 -                              int len = skb->len;
 -                              struct sta_info *sta;
 -
 -                              rcu_read_lock();
 -                              sta = sta_info_get(sdata, mgmt->sa);
 -                              if (!sta) {
 -                                      rcu_read_unlock();
 -                                      break;
 -                              }
 -
 -                              local_bh_disable();
 -
 -                              switch (mgmt->u.action.u.addba_req.action_code) {
 -                              case WLAN_ACTION_ADDBA_REQ:
 -                                      if (len < (IEEE80211_MIN_ACTION_SIZE +
 -                                                 sizeof(mgmt->u.action.u.addba_req)))
 -                                              break;
 -                                      ieee80211_process_addba_request(local, sta, mgmt, len);
 -                                      break;
 -                              case WLAN_ACTION_ADDBA_RESP:
 -                                      if (len < (IEEE80211_MIN_ACTION_SIZE +
 -                                                 sizeof(mgmt->u.action.u.addba_resp)))
 -                                              break;
 -                                      ieee80211_process_addba_resp(local, sta, mgmt, len);
 -                                      break;
 -                              case WLAN_ACTION_DELBA:
 -                                      if (len < (IEEE80211_MIN_ACTION_SIZE +
 -                                                 sizeof(mgmt->u.action.u.delba)))
 -                                              break;
 -                                      ieee80211_process_delba(sdata, sta, mgmt, len);
 -                                      break;
 -                              }
 -                              local_bh_enable();
 -                              rcu_read_unlock();
 -                              break;
 -                              }
                        case WLAN_CATEGORY_SPECTRUM_MGMT:
                                ieee80211_sta_process_chanswitch(sdata,
                                                &mgmt->u.action.u.chan_switch.sw_elem,
                default:
                        WARN(1, "unexpected: %d", rma);
                }
 -              goto out;
 +              return;
        }
  
        mutex_unlock(&ifmgd->mtx);
  
        if (skb->len >= 24 + 2 /* mgmt + deauth reason */ &&
-           (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH)
+           (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) {
+               struct ieee80211_local *local = sdata->local;
+               struct ieee80211_work *wk;
+               mutex_lock(&local->work_mtx);
+               list_for_each_entry(wk, &local->work_list, list) {
+                       if (wk->sdata != sdata)
+                               continue;
+                       if (wk->type != IEEE80211_WORK_ASSOC)
+                               continue;
+                       if (memcmp(mgmt->bssid, wk->filter_ta, ETH_ALEN))
+                               continue;
+                       if (memcmp(mgmt->sa, wk->filter_ta, ETH_ALEN))
+                               continue;
+                       /*
+                        * Printing the message only here means we can't
+                        * spuriously print it, but it also means that it
+                        * won't be printed when the frame comes in before
+                        * we even tried to associate or in similar cases.
+                        *
+                        * Ultimately, I suspect cfg80211 should print the
+                        * messages instead.
+                        */
+                       printk(KERN_DEBUG
+                              "%s: deauthenticated from %pM (Reason: %u)\n",
+                              sdata->name, mgmt->bssid,
+                              le16_to_cpu(mgmt->u.deauth.reason_code));
+                       list_del_rcu(&wk->list);
+                       free_work(wk);
+                       break;
+               }
+               mutex_unlock(&local->work_mtx);
                cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
 - out:
 -      kfree_skb(skb);
+       }
  }
  
  static void ieee80211_sta_timer(unsigned long data)
                return;
        }
  
 -      ieee80211_queue_work(&local->hw, &ifmgd->work);
 +      ieee80211_queue_work(&local->hw, &sdata->work);
  }
  
 -static void ieee80211_sta_work(struct work_struct *work)
 +void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
  {
 -      struct ieee80211_sub_if_data *sdata =
 -              container_of(work, struct ieee80211_sub_if_data, u.mgd.work);
        struct ieee80211_local *local = sdata->local;
 -      struct ieee80211_if_managed *ifmgd;
 -      struct sk_buff *skb;
 -
 -      if (!ieee80211_sdata_running(sdata))
 -              return;
 -
 -      if (local->scanning)
 -              return;
 -
 -      if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
 -              return;
 -
 -      /*
 -       * ieee80211_queue_work() should have picked up most cases,
 -       * here we'll pick the the rest.
 -       */
 -      if (WARN(local->suspended, "STA MLME work scheduled while "
 -               "going to suspend\n"))
 -              return;
 -
 -      ifmgd = &sdata->u.mgd;
 -
 -      /* first process frames to avoid timing out while a frame is pending */
 -      while ((skb = skb_dequeue(&ifmgd->skb_queue)))
 -              ieee80211_sta_rx_queued_mgmt(sdata, skb);
 +      struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
  
        /* then process the rest of the work */
        mutex_lock(&ifmgd->mtx);
@@@ -1821,7 -1942,8 +1858,7 @@@ static void ieee80211_restart_sta_timer
                ieee80211_queue_work(&sdata->local->hw,
                           &sdata->u.mgd.monitor_work);
                /* and do all the other regular work too */
 -              ieee80211_queue_work(&sdata->local->hw,
 -                         &sdata->u.mgd.work);
 +              ieee80211_queue_work(&sdata->local->hw, &sdata->work);
        }
  }
  
@@@ -1836,6 -1958,7 +1873,6 @@@ void ieee80211_sta_quiesce(struct ieee8
         * time -- the code here is properly synchronised.
         */
  
 -      cancel_work_sync(&ifmgd->work);
        cancel_work_sync(&ifmgd->beacon_connection_loss_work);
        if (del_timer_sync(&ifmgd->timer))
                set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
@@@ -1867,6 -1990,7 +1904,6 @@@ void ieee80211_sta_setup_sdata(struct i
        struct ieee80211_if_managed *ifmgd;
  
        ifmgd = &sdata->u.mgd;
 -      INIT_WORK(&ifmgd->work, ieee80211_sta_work);
        INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work);
        INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
        INIT_WORK(&ifmgd->beacon_connection_loss_work,
                    (unsigned long) sdata);
        setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,
                    (unsigned long) sdata);
 -      skb_queue_head_init(&ifmgd->skb_queue);
  
        ifmgd->flags = 0;
  
@@@ -2028,7 -2153,6 +2065,7 @@@ static enum work_done_result ieee80211_
                                                    wk->filter_ta);
                        return WORK_DONE_DESTROY;
                }
 +
                mutex_unlock(&wk->sdata->u.mgd.mtx);
        }
  
@@@ -2158,16 -2282,14 +2195,16 @@@ int ieee80211_mgd_deauth(struct ieee802
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_work *wk;
 -      const u8 *bssid = req->bss->bssid;
 +      u8 bssid[ETH_ALEN];
 +      bool assoc_bss = false;
  
        mutex_lock(&ifmgd->mtx);
  
 +      memcpy(bssid, req->bss->bssid, ETH_ALEN);
        if (ifmgd->associated == req->bss) {
 -              bssid = req->bss->bssid;
 -              ieee80211_set_disassoc(sdata, true);
 +              ieee80211_set_disassoc(sdata, false);
                mutex_unlock(&ifmgd->mtx);
 +              assoc_bss = true;
        } else {
                bool not_auth_yet = false;
  
        ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH,
                                       req->reason_code, cookie,
                                       !req->local_state_change);
 +      if (assoc_bss)
 +              sta_info_destroy_addr(sdata, bssid);
  
        ieee80211_recalc_idle(sdata->local);
  
@@@ -2259,6 -2379,41 +2296,6 @@@ int ieee80211_mgd_disassoc(struct ieee8
        return 0;
  }
  
 -int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
 -                       struct ieee80211_channel *chan,
 -                       enum nl80211_channel_type channel_type,
 -                       const u8 *buf, size_t len, u64 *cookie)
 -{
 -      struct ieee80211_local *local = sdata->local;
 -      struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 -      struct sk_buff *skb;
 -
 -      /* Check that we are on the requested channel for transmission */
 -      if ((chan != local->tmp_channel ||
 -           channel_type != local->tmp_channel_type) &&
 -          (chan != local->oper_channel ||
 -           channel_type != local->_oper_channel_type))
 -              return -EBUSY;
 -
 -      skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
 -      if (!skb)
 -              return -ENOMEM;
 -      skb_reserve(skb, local->hw.extra_tx_headroom);
 -
 -      memcpy(skb_put(skb, len), buf, len);
 -
 -      if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
 -              IEEE80211_SKB_CB(skb)->flags |=
 -                      IEEE80211_TX_INTFL_DONT_ENCRYPT;
 -      IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX |
 -              IEEE80211_TX_CTL_REQ_TX_STATUS;
 -      skb->dev = sdata->dev;
 -      ieee80211_tx_skb(sdata, skb);
 -
 -      *cookie = (unsigned long) skb;
 -      return 0;
 -}
 -
  void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
                               enum nl80211_cqm_rssi_threshold_event rssi_event,
                               gfp_t gfp)
diff --combined net/mac80211/work.c
index 4157717ed786cae0359fd005966934c50213b1c7,b025dc7bb0fd4e1decb356709cb3ac5d3163db58..c22a71c5cb454c6d2b8ad646dc7b0559d90689f0
@@@ -715,7 -715,7 +715,7 @@@ static void ieee80211_work_rx_queued_mg
        struct ieee80211_rx_status *rx_status;
        struct ieee80211_mgmt *mgmt;
        struct ieee80211_work *wk;
-       enum work_action rma;
+       enum work_action rma = WORK_ACT_NONE;
        u16 fc;
  
        rx_status = (struct ieee80211_rx_status *) skb->cb;
@@@ -840,7 -840,7 +840,7 @@@ static void ieee80211_work_work(struct 
  
        /*
         * ieee80211_queue_work() should have picked up most cases,
 -       * here we'll pick the the rest.
 +       * here we'll pick the rest.
         */
        if (WARN(local->suspended, "work scheduled while going to suspend\n"))
                return;
This page took 0.123614 seconds and 4 git commands to generate.