diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2008-06-30 05:23:06 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-06-30 17:37:39 -0400 |
commit | 43d59b323743b8a01e9ad1a1b31b0d7c0ef6e35a (patch) | |
tree | 8329613e007265c0fc0d4dfb959f7dff69fbdace /drivers/net/wireless/iwlwifi | |
parent | ebbbdc3fb70ebb4dae1d319b723c14b5dc21cc71 (diff) |
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 <emmanuel.grumbach@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl4965-base.c | 79 |
1 files changed, 46 insertions, 33 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index a2dffe401c78..0a279d15e058 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) | |||
241 | /* cast away the const for active_rxon in this function */ | 241 | /* cast away the const for active_rxon in this function */ |
242 | struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; | 242 | struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; |
243 | DECLARE_MAC_BUF(mac); | 243 | DECLARE_MAC_BUF(mac); |
244 | int rc = 0; | 244 | int ret; |
245 | bool new_assoc = | ||
246 | !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK); | ||
245 | 247 | ||
246 | if (!iwl_is_alive(priv)) | 248 | if (!iwl_is_alive(priv)) |
247 | return -1; | 249 | return -EBUSY; |
248 | 250 | ||
249 | /* always get timestamp with Rx frame */ | 251 | /* always get timestamp with Rx frame */ |
250 | priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; | 252 | priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; |
251 | 253 | ||
252 | rc = iwl4965_check_rxon_cmd(&priv->staging_rxon); | 254 | ret = iwl4965_check_rxon_cmd(&priv->staging_rxon); |
253 | if (rc) { | 255 | if (ret) { |
254 | IWL_ERROR("Invalid RXON configuration. Not committing.\n"); | 256 | IWL_ERROR("Invalid RXON configuration. Not committing.\n"); |
255 | return -EINVAL; | 257 | return -EINVAL; |
256 | } | 258 | } |
@@ -259,15 +261,13 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) | |||
259 | * iwl4965_rxon_assoc_cmd which is used to reconfigure filter | 261 | * iwl4965_rxon_assoc_cmd which is used to reconfigure filter |
260 | * and other flags for the current radio configuration. */ | 262 | * and other flags for the current radio configuration. */ |
261 | if (!iwl4965_full_rxon_required(priv)) { | 263 | if (!iwl4965_full_rxon_required(priv)) { |
262 | rc = iwl_send_rxon_assoc(priv); | 264 | ret = iwl_send_rxon_assoc(priv); |
263 | if (rc) { | 265 | if (ret) { |
264 | IWL_ERROR("Error setting RXON_ASSOC " | 266 | IWL_ERROR("Error setting RXON_ASSOC (%d)\n", ret); |
265 | "configuration (%d).\n", rc); | 267 | return ret; |
266 | return rc; | ||
267 | } | 268 | } |
268 | 269 | ||
269 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); | 270 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); |
270 | |||
271 | return 0; | 271 | return 0; |
272 | } | 272 | } |
273 | 273 | ||
@@ -278,22 +278,20 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) | |||
278 | * an RXON_ASSOC and the new config wants the associated mask enabled, | 278 | * an RXON_ASSOC and the new config wants the associated mask enabled, |
279 | * we must clear the associated from the active configuration | 279 | * we must clear the associated from the active configuration |
280 | * before we apply the new config */ | 280 | * before we apply the new config */ |
281 | if (iwl_is_associated(priv) && | 281 | if (iwl_is_associated(priv) && new_assoc) { |
282 | (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) { | ||
283 | IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); | 282 | IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); |
284 | active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; | 283 | active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; |
285 | 284 | ||
286 | rc = iwl_send_cmd_pdu(priv, REPLY_RXON, | 285 | ret = iwl_send_cmd_pdu(priv, REPLY_RXON, |
287 | sizeof(struct iwl_rxon_cmd), | 286 | sizeof(struct iwl_rxon_cmd), |
288 | &priv->active_rxon); | 287 | &priv->active_rxon); |
289 | 288 | ||
290 | /* If the mask clearing failed then we set | 289 | /* If the mask clearing failed then we set |
291 | * active_rxon back to what it was previously */ | 290 | * active_rxon back to what it was previously */ |
292 | if (rc) { | 291 | if (ret) { |
293 | active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; | 292 | active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; |
294 | IWL_ERROR("Error clearing ASSOC_MSK on current " | 293 | IWL_ERROR("Error clearing ASSOC_MSK (%d)\n", ret); |
295 | "configuration (%d).\n", rc); | 294 | return ret; |
296 | return rc; | ||
297 | } | 295 | } |
298 | } | 296 | } |
299 | 297 | ||
@@ -301,18 +299,25 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) | |||
301 | "* with%s RXON_FILTER_ASSOC_MSK\n" | 299 | "* with%s RXON_FILTER_ASSOC_MSK\n" |
302 | "* channel = %d\n" | 300 | "* channel = %d\n" |
303 | "* bssid = %s\n", | 301 | "* bssid = %s\n", |
304 | ((priv->staging_rxon.filter_flags & | 302 | (new_assoc ? "" : "out"), |
305 | RXON_FILTER_ASSOC_MSK) ? "" : "out"), | ||
306 | le16_to_cpu(priv->staging_rxon.channel), | 303 | le16_to_cpu(priv->staging_rxon.channel), |
307 | print_mac(mac, priv->staging_rxon.bssid_addr)); | 304 | print_mac(mac, priv->staging_rxon.bssid_addr)); |
308 | 305 | ||
309 | iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); | 306 | iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); |
310 | /* Apply the new configuration */ | 307 | |
311 | rc = iwl_send_cmd_pdu(priv, REPLY_RXON, | 308 | /* Apply the new configuration |
309 | * RXON unassoc clears the station table in uCode, send it before | ||
310 | * we add the bcast station. If assoc bit is set, we will send RXON | ||
311 | * after having added the bcast and bssid station. | ||
312 | */ | ||
313 | if (!new_assoc) { | ||
314 | ret = iwl_send_cmd_pdu(priv, REPLY_RXON, | ||
312 | sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); | 315 | sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); |
313 | if (rc) { | 316 | if (ret) { |
314 | IWL_ERROR("Error setting new configuration (%d).\n", rc); | 317 | IWL_ERROR("Error setting new RXON (%d)\n", ret); |
315 | return rc; | 318 | return ret; |
319 | } | ||
320 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); | ||
316 | } | 321 | } |
317 | 322 | ||
318 | iwlcore_clear_stations_table(priv); | 323 | iwlcore_clear_stations_table(priv); |
@@ -322,27 +327,24 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) | |||
322 | 327 | ||
323 | iwl_init_sensitivity(priv); | 328 | iwl_init_sensitivity(priv); |
324 | 329 | ||
325 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); | ||
326 | |||
327 | /* If we issue a new RXON command which required a tune then we must | 330 | /* If we issue a new RXON command which required a tune then we must |
328 | * send a new TXPOWER command or we won't be able to Tx any frames */ | 331 | * send a new TXPOWER command or we won't be able to Tx any frames */ |
329 | rc = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); | 332 | ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); |
330 | if (rc) { | 333 | if (ret) { |
331 | IWL_ERROR("Error sending TX power (%d).\n", rc); | 334 | IWL_ERROR("Error sending TX power (%d)\n", ret); |
332 | return rc; | 335 | return ret; |
333 | } | 336 | } |
334 | 337 | ||
335 | /* Add the broadcast address so we can send broadcast frames */ | 338 | /* Add the broadcast address so we can send broadcast frames */ |
336 | if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) == | 339 | if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) == |
337 | IWL_INVALID_STATION) { | 340 | IWL_INVALID_STATION) { |
338 | IWL_ERROR("Error adding BROADCAST address for transmit.\n"); | 341 | IWL_ERROR("Error adding BROADCAST address for transmit.\n"); |
339 | return -EIO; | 342 | return -EIO; |
340 | } | 343 | } |
341 | 344 | ||
342 | /* If we have set the ASSOC_MSK and we are in BSS mode then | 345 | /* If we have set the ASSOC_MSK and we are in BSS mode then |
343 | * add the IWL_AP_ID to the station rate table */ | 346 | * add the IWL_AP_ID to the station rate table */ |
344 | if (iwl_is_associated(priv) && | 347 | if (new_assoc && (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { |
345 | (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { | ||
346 | if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) | 348 | if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) |
347 | == IWL_INVALID_STATION) { | 349 | == IWL_INVALID_STATION) { |
348 | IWL_ERROR("Error adding AP address for transmit.\n"); | 350 | IWL_ERROR("Error adding AP address for transmit.\n"); |
@@ -352,6 +354,17 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) | |||
352 | if (priv->default_wep_key && | 354 | if (priv->default_wep_key && |
353 | iwl_send_static_wepkey_cmd(priv, 0)) | 355 | iwl_send_static_wepkey_cmd(priv, 0)) |
354 | IWL_ERROR("Could not send WEP static key.\n"); | 356 | IWL_ERROR("Could not send WEP static key.\n"); |
357 | |||
358 | /* Apply the new configuration | ||
359 | * RXON assoc doesn't clear the station table in uCode, | ||
360 | */ | ||
361 | ret = iwl_send_cmd_pdu(priv, REPLY_RXON, | ||
362 | sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); | ||
363 | if (ret) { | ||
364 | IWL_ERROR("Error setting new RXON (%d)\n", ret); | ||
365 | return ret; | ||
366 | } | ||
367 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); | ||
355 | } | 368 | } |
356 | 369 | ||
357 | return 0; | 370 | return 0; |