]> err.no Git - linux-2.6/blobdiff - drivers/net/wireless/iwlwifi/iwl4965-base.c
iwlwifi: fix incorrect monitor mode operation
[linux-2.6] / drivers / net / wireless / iwlwifi / iwl4965-base.c
index a87e870f96d0614408c6556cb9d8468f5e356af8..ba0f28945eb1f37c11241867545030a16dd676fb 100644 (file)
@@ -344,16 +344,19 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
 
        /* If we have set the ASSOC_MSK and we are in BSS mode then
         * add the IWL_AP_ID to the station rate table */
-       if (new_assoc && (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
-               if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1)
-                   == IWL_INVALID_STATION) {
-                       IWL_ERROR("Error adding AP address for transmit.\n");
-                       return -EIO;
+       if (new_assoc) {
+               if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+                       ret = iwl_rxon_add_station(priv,
+                                          priv->active_rxon.bssid_addr, 1);
+                       if (ret == IWL_INVALID_STATION) {
+                               IWL_ERROR("Error adding AP address for TX.\n");
+                               return -EIO;
+                       }
+                       priv->assoc_station_added = 1;
+                       if (priv->default_wep_key &&
+                           iwl_send_static_wepkey_cmd(priv, 0))
+                               IWL_ERROR("Could not send WEP static key.\n");
                }
-               priv->assoc_station_added = 1;
-               if (priv->default_wep_key &&
-                   iwl_send_static_wepkey_cmd(priv, 0))
-                       IWL_ERROR("Could not send WEP static key.\n");
 
                /* Apply the new configuration
                 * RXON assoc doesn't clear the station table in uCode,
@@ -755,7 +758,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv)
 #endif
 
        ch_info = iwl_get_channel_info(priv, priv->band,
-                                      le16_to_cpu(priv->staging_rxon.channel));
+                                      le16_to_cpu(priv->active_rxon.channel));
 
        if (!ch_info)
                ch_info = &priv->channel_info[0];
@@ -791,9 +794,6 @@ static int iwl4965_set_mode(struct iwl_priv *priv, int mode)
 {
        priv->iw_mode = mode;
 
-       /* init channel/phymode to values given at driver init */
-       iwl_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
-
        iwl4965_connection_init_rx_config(priv);
        memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
 
@@ -1603,14 +1603,12 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
                IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n",
                                hw_rf_kill ? "disable radio":"enable radio");
 
-               /* Queue restart only if RF_KILL switch was set to "kill"
-                *   when we loaded driver, and is now set to "enable".
-                * After we're Alive, RF_KILL gets handled by
-                *   iwl4965_rx_card_state_notif() */
-               if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) {
+               /* driver only loads ucode once setting the interface up.
+                * the driver as well won't allow loading if RFKILL is set
+                * therefore no need to restart the driver from this handler
+                */
+               if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status))
                        clear_bit(STATUS_RF_KILL_HW, &priv->status);
-                       queue_work(priv->workqueue, &priv->restart);
-               }
 
                handled |= CSR_INT_BIT_RF_KILL;
        }
@@ -2100,7 +2098,9 @@ static void __iwl4965_down(struct iwl_priv *priv)
                               test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
                                        STATUS_GEO_CONFIGURED |
                               test_bit(STATUS_IN_SUSPEND, &priv->status) <<
-                                       STATUS_IN_SUSPEND;
+                                       STATUS_IN_SUSPEND |
+                              test_bit(STATUS_EXIT_PENDING, &priv->status) <<
+                                       STATUS_EXIT_PENDING;
                goto exit;
        }
 
@@ -2115,7 +2115,9 @@ static void __iwl4965_down(struct iwl_priv *priv)
                        test_bit(STATUS_IN_SUSPEND, &priv->status) <<
                                STATUS_IN_SUSPEND |
                        test_bit(STATUS_FW_ERROR, &priv->status) <<
-                               STATUS_FW_ERROR;
+                               STATUS_FW_ERROR |
+                      test_bit(STATUS_EXIT_PENDING, &priv->status) <<
+                               STATUS_EXIT_PENDING;
 
        spin_lock_irqsave(&priv->lock, flags);
        iwl_clear_bit(priv, CSR_GP_CNTRL,
@@ -2180,13 +2182,15 @@ static int __iwl4965_up(struct iwl_priv *priv)
        if (iwl_read32(priv, CSR_GP_CNTRL) &
                                CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
                clear_bit(STATUS_RF_KILL_HW, &priv->status);
-       else {
+       else
                set_bit(STATUS_RF_KILL_HW, &priv->status);
-               if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) {
-                       iwl_rfkill_set_hw_state(priv);
-                       IWL_WARNING("Radio disabled by HW RF Kill switch\n");
-                       return -ENODEV;
-               }
+
+       if (!test_bit(STATUS_IN_SUSPEND, &priv->status) &&
+           iwl_is_rfkill(priv)) {
+               iwl_rfkill_set_hw_state(priv);
+               IWL_WARNING("Radio disabled by %s RF Kill switch\n",
+                   test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW");
+               return -ENODEV;
        }
 
        iwl_rfkill_set_hw_state(priv);
@@ -2483,7 +2487,6 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
 
        switch (priv->iw_mode) {
        case IEEE80211_IF_TYPE_STA:
-               iwl4965_rate_scale_init(priv->hw, IWL_AP_ID);
                break;
 
        case IEEE80211_IF_TYPE_IBSS:
@@ -2492,7 +2495,6 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
                priv->assoc_id = 1;
 
                iwl_rxon_add_station(priv, priv->bssid, 0);
-               iwl4965_rate_scale_init(priv->hw, IWL_STA_ID);
                iwl4965_send_beacon_cmd(priv);
 
                break;
@@ -2559,7 +2561,7 @@ static void iwl_bg_scan_completed(struct work_struct *work)
  *
  *****************************************************************************/
 
-#define UCODE_READY_TIMEOUT    (2 * HZ)
+#define UCODE_READY_TIMEOUT    (4 * HZ)
 
 static int iwl4965_mac_start(struct ieee80211_hw *hw)
 {
@@ -2612,21 +2614,19 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
 
        /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from
         * mac80211 will not be run successfully. */
-       if (priv->ucode_type == UCODE_RT) {
-               ret = wait_event_interruptible_timeout(priv->wait_command_queue,
-                               test_bit(STATUS_READY, &priv->status),
-                               UCODE_READY_TIMEOUT);
-               if (!ret) {
-                       if (!test_bit(STATUS_READY, &priv->status)) {
-                               IWL_ERROR("START_ALIVE timeout after %dms.\n",
-                                       jiffies_to_msecs(UCODE_READY_TIMEOUT));
-                               ret = -ETIMEDOUT;
-                               goto out_release_irq;
-                       }
+       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+                       test_bit(STATUS_READY, &priv->status),
+                       UCODE_READY_TIMEOUT);
+       if (!ret) {
+               if (!test_bit(STATUS_READY, &priv->status)) {
+                       IWL_ERROR("START_ALIVE timeout after %dms.\n",
+                               jiffies_to_msecs(UCODE_READY_TIMEOUT));
+                       ret = -ETIMEDOUT;
+                       goto out_release_irq;
                }
-
-               priv->is_open = 1;
        }
+
+       priv->is_open = 1;
        IWL_DEBUG_MAC80211("leave\n");
        return 0;
 
@@ -3022,26 +3022,18 @@ static void iwl4965_configure_filter(struct ieee80211_hw *hw,
                                 unsigned int *total_flags,
                                 int mc_count, struct dev_addr_list *mc_list)
 {
-       /*
-        * XXX: dummy
-        * see also iwl4965_connection_init_rx_config
-        */
        struct iwl_priv *priv = hw->priv;
-       int new_flags = 0;
-       if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
-               if (*total_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
-                       IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
-                                          IEEE80211_IF_TYPE_MNTR,
-                                          changed_flags, *total_flags);
-                       /* queue work 'cuz mac80211 is holding a lock which
-                        * prevents us from issuing (synchronous) f/w cmds */
-                       queue_work(priv->workqueue, &priv->set_monitor);
-                       new_flags &= FIF_PROMISC_IN_BSS |
-                                    FIF_OTHER_BSS |
-                                    FIF_ALLMULTI;
-               }
+
+       if (changed_flags & (*total_flags) & FIF_OTHER_BSS) {
+               IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
+                                  IEEE80211_IF_TYPE_MNTR,
+                                  changed_flags, *total_flags);
+               /* queue work 'cuz mac80211 is holding a lock which
+                * prevents us from issuing (synchronous) f/w cmds */
+               queue_work(priv->workqueue, &priv->set_monitor);
        }
-       *total_flags = new_flags;
+       *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI |
+                       FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
 }
 
 static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
@@ -3406,17 +3398,6 @@ static int iwl4965_mac_get_stats(struct ieee80211_hw *hw,
        return 0;
 }
 
-static u64 iwl4965_mac_get_tsf(struct ieee80211_hw *hw)
-{
-       struct iwl_priv *priv;
-
-       priv = hw->priv;
-       IWL_DEBUG_MAC80211("enter\n");
-       IWL_DEBUG_MAC80211("leave\n");
-
-       return 0;
-}
-
 static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
 {
        struct iwl_priv *priv = hw->priv;
@@ -3425,7 +3406,6 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
        mutex_lock(&priv->mutex);
        IWL_DEBUG_MAC80211("enter\n");
 
-       priv->lq_mngr.lq_ready = 0;
        spin_lock_irqsave(&priv->lock, flags);
        memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info));
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -3488,6 +3468,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
 {
        struct iwl_priv *priv = hw->priv;
        unsigned long flags;
+       __le64 timestamp;
 
        mutex_lock(&priv->mutex);
        IWL_DEBUG_MAC80211("enter\n");
@@ -3512,6 +3493,8 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
        priv->ibss_beacon = skb;
 
        priv->assoc_id = 0;
+       timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
+       priv->timestamp = le64_to_cpu(timestamp) +  (priv->beacon_int * 1000);
 
        IWL_DEBUG_MAC80211("leave\n");
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -4105,7 +4088,6 @@ static struct ieee80211_ops iwl4965_hw_ops = {
        .get_stats = iwl4965_mac_get_stats,
        .get_tx_stats = iwl4965_mac_get_tx_stats,
        .conf_tx = iwl4965_mac_conf_tx,
-       .get_tsf = iwl4965_mac_get_tsf,
        .reset_tsf = iwl4965_mac_reset_tsf,
        .beacon_update = iwl4965_mac_beacon_update,
        .bss_info_changed = iwl4965_bss_info_changed,
@@ -4234,8 +4216,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        /************************
         * 5. Setup HW constants
         ************************/
-       /* Device-specific setup */
-       if (priv->cfg->ops->lib->set_hw_params(priv)) {
+       if (iwl_set_hw_params(priv)) {
                IWL_ERROR("failed to set hw parameters\n");
                goto out_free_eeprom;
        }