From 43d59b323743b8a01e9ad1a1b31b0d7c0ef6e35a Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 30 Jun 2008 17:23:06 +0800 Subject: iwlwifi: send ADD_STA before RXON with assoc bit This patch fixes a bug in association flow. As soon as RXON with assoc bit is sent, uCode expects to have an entry in its station table that describe the AP. Receiving a beacon from an HT AP before sending ADD_STA results a uCode error. This patch sends first the ADD_STA (bcast and bssid) and only then RXON with assoc bit set Signed-off-by: Emmanuel Grumbach Signed-off-by: Gregory Greenman Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl4965-base.c | 79 +++++++++++++++++------------ 1 file changed, 46 insertions(+), 33 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index a2dffe401c7..0a279d15e05 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -241,16 +241,18 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) /* cast away the const for active_rxon in this function */ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; DECLARE_MAC_BUF(mac); - int rc = 0; + int ret; + bool new_assoc = + !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK); if (!iwl_is_alive(priv)) - return -1; + return -EBUSY; /* always get timestamp with Rx frame */ priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; - rc = iwl4965_check_rxon_cmd(&priv->staging_rxon); - if (rc) { + ret = iwl4965_check_rxon_cmd(&priv->staging_rxon); + if (ret) { IWL_ERROR("Invalid RXON configuration. Not committing.\n"); return -EINVAL; } @@ -259,15 +261,13 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) * iwl4965_rxon_assoc_cmd which is used to reconfigure filter * and other flags for the current radio configuration. */ if (!iwl4965_full_rxon_required(priv)) { - rc = iwl_send_rxon_assoc(priv); - if (rc) { - IWL_ERROR("Error setting RXON_ASSOC " - "configuration (%d).\n", rc); - return rc; + ret = iwl_send_rxon_assoc(priv); + if (ret) { + IWL_ERROR("Error setting RXON_ASSOC (%d)\n", ret); + return ret; } memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); - return 0; } @@ -278,22 +278,20 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) * an RXON_ASSOC and the new config wants the associated mask enabled, * we must clear the associated from the active configuration * before we apply the new config */ - if (iwl_is_associated(priv) && - (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) { + if (iwl_is_associated(priv) && new_assoc) { IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, + ret = iwl_send_cmd_pdu(priv, REPLY_RXON, sizeof(struct iwl_rxon_cmd), &priv->active_rxon); /* If the mask clearing failed then we set * active_rxon back to what it was previously */ - if (rc) { + if (ret) { active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; - IWL_ERROR("Error clearing ASSOC_MSK on current " - "configuration (%d).\n", rc); - return rc; + IWL_ERROR("Error clearing ASSOC_MSK (%d)\n", ret); + return ret; } } @@ -301,18 +299,25 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) "* with%s RXON_FILTER_ASSOC_MSK\n" "* channel = %d\n" "* bssid = %s\n", - ((priv->staging_rxon.filter_flags & - RXON_FILTER_ASSOC_MSK) ? "" : "out"), + (new_assoc ? "" : "out"), le16_to_cpu(priv->staging_rxon.channel), print_mac(mac, priv->staging_rxon.bssid_addr)); iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); - /* Apply the new configuration */ - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, + + /* Apply the new configuration + * RXON unassoc clears the station table in uCode, send it before + * we add the bcast station. If assoc bit is set, we will send RXON + * after having added the bcast and bssid station. + */ + if (!new_assoc) { + ret = iwl_send_cmd_pdu(priv, REPLY_RXON, sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); - if (rc) { - IWL_ERROR("Error setting new configuration (%d).\n", rc); - return rc; + if (ret) { + IWL_ERROR("Error setting new RXON (%d)\n", ret); + return ret; + } + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); } iwlcore_clear_stations_table(priv); @@ -322,27 +327,24 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) iwl_init_sensitivity(priv); - memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); - /* If we issue a new RXON command which required a tune then we must * send a new TXPOWER command or we won't be able to Tx any frames */ - rc = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); - if (rc) { - IWL_ERROR("Error sending TX power (%d).\n", rc); - return rc; + ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); + if (ret) { + IWL_ERROR("Error sending TX power (%d)\n", ret); + return ret; } /* Add the broadcast address so we can send broadcast frames */ if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) == - IWL_INVALID_STATION) { + IWL_INVALID_STATION) { IWL_ERROR("Error adding BROADCAST address for transmit.\n"); return -EIO; } /* 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 (iwl_is_associated(priv) && - (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { + 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"); @@ -352,6 +354,17 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) 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, + */ + ret = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); + if (ret) { + IWL_ERROR("Error setting new RXON (%d)\n", ret); + return ret; + } + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); } return 0; -- cgit v1.2.3