iwlagn: handle GO powersave
authorJohannes Berg <johannes.berg@intel.com>
Fri, 26 Aug 2011 06:13:56 +0000 (23:13 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 29 Aug 2011 19:33:01 +0000 (15:33 -0400)
In order to implement support for GO powersave on
the P2P client side, the ucode needs to know what
GO we're trying to authenticate/associate with,
it needs to have a station entry and the BSSID in
the RXON set.

Implement the new mac80211 callbacks to give this
data to the device.

Since this is also useful for the device when a
normal connection is established, also program it
with the information in that case.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-dev.h

index b4d7460f05caa6763a2962f78337a0b0a57d2502..1af276739d875f522d43ef0dad29d91889381c67 100644 (file)
@@ -435,6 +435,10 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        if (!ctx->is_active)
                return 0;
 
+       /* override BSSID if necessary due to preauth */
+       if (ctx->preauth_bssid)
+               memcpy(ctx->staging.bssid_addr, ctx->bssid, ETH_ALEN);
+
        /* always get timestamp with Rx frame */
        ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
 
@@ -897,6 +901,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
                if (!priv->disable_chain_noise_cal)
                        iwlagn_chain_noise_reset(priv);
                priv->start_calib = 1;
+               WARN_ON(ctx->preauth_bssid);
        }
 
        if (changes & BSS_CHANGED_IBSS) {
index a0cf486f76251e967ad61602e0f40043865365d4..8113fbe770a3da676a0dec2ef95077b2dd3c4851 100644 (file)
@@ -2956,6 +2956,72 @@ static int iwl_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
        return 0;
 }
 
+static int iwl_mac_tx_sync(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                          const u8 *bssid, enum ieee80211_tx_sync_type type)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+       int ret;
+       u8 sta_id;
+
+       mutex_lock(&priv->shrd->mutex);
+
+       if (iwl_is_associated_ctx(ctx)) {
+               ret = 0;
+               goto out;
+       }
+
+       if (ctx->preauth_bssid || test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       ret = iwl_add_station_common(priv, ctx, bssid, true, NULL, &sta_id);
+       if (ret)
+               goto out;
+
+       if (WARN_ON(sta_id != ctx->ap_sta_id)) {
+               ret = -EIO;
+               goto out_remove_sta;
+       }
+
+       memcpy(ctx->bssid, bssid, ETH_ALEN);
+       ctx->preauth_bssid = true;
+
+       ret = iwlagn_commit_rxon(priv, ctx);
+
+       if (ret == 0)
+               goto out;
+
+ out_remove_sta:
+       iwl_remove_station(priv, sta_id, bssid);
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       return ret;
+}
+
+static void iwl_mac_finish_tx_sync(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  const u8 *bssid,
+                                  enum ieee80211_tx_sync_type type)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+
+       mutex_lock(&priv->shrd->mutex);
+
+       if (iwl_is_associated_ctx(ctx))
+               goto out;
+
+       iwl_remove_station(priv, ctx->ap_sta_id, bssid);
+       ctx->preauth_bssid = false;
+       /* no need to commit */
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+}
+
 /*****************************************************************************
  *
  * driver setup and teardown
@@ -3164,6 +3230,8 @@ struct ieee80211_ops iwlagn_hw_ops = {
        .rssi_callback = iwl_mac_rssi_callback,
        CFG80211_TESTMODE_CMD(iwl_testmode_cmd)
        CFG80211_TESTMODE_DUMP(iwl_testmode_dump)
+       .tx_sync = iwl_mac_tx_sync,
+       .finish_tx_sync = iwl_mac_finish_tx_sync,
 };
 
 static u32 iwl_hw_detect(struct iwl_priv *priv)
index 33a829ad7e2a057bec28621443eda28c671ddfc5..1e54293532b0f1f0d4aac3925af1c86d5a7fe69a 100644 (file)
@@ -992,6 +992,9 @@ struct iwl_rxon_context {
                u8 extension_chan_offset;
        } ht;
 
+       u8 bssid[ETH_ALEN];
+       bool preauth_bssid;
+
        bool last_tx_rejected;
 };