diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-rxon.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 103 |
1 files changed, 58 insertions, 45 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 2d927a94074d..203ee60a82b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | |||
@@ -72,6 +72,34 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, | |||
72 | return ret; | 72 | return ret; |
73 | } | 73 | } |
74 | 74 | ||
75 | static void iwlagn_update_qos(struct iwl_priv *priv, | ||
76 | struct iwl_rxon_context *ctx) | ||
77 | { | ||
78 | int ret; | ||
79 | |||
80 | if (!ctx->is_active) | ||
81 | return; | ||
82 | |||
83 | ctx->qos_data.def_qos_parm.qos_flags = 0; | ||
84 | |||
85 | if (ctx->qos_data.qos_active) | ||
86 | ctx->qos_data.def_qos_parm.qos_flags |= | ||
87 | QOS_PARAM_FLG_UPDATE_EDCA_MSK; | ||
88 | |||
89 | if (ctx->ht.enabled) | ||
90 | ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; | ||
91 | |||
92 | IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", | ||
93 | ctx->qos_data.qos_active, | ||
94 | ctx->qos_data.def_qos_parm.qos_flags); | ||
95 | |||
96 | ret = iwl_send_cmd_pdu(priv, ctx->qos_cmd, | ||
97 | sizeof(struct iwl_qosparam_cmd), | ||
98 | &ctx->qos_data.def_qos_parm); | ||
99 | if (ret) | ||
100 | IWL_ERR(priv, "Failed to update QoS\n"); | ||
101 | } | ||
102 | |||
75 | static int iwlagn_update_beacon(struct iwl_priv *priv, | 103 | static int iwlagn_update_beacon(struct iwl_priv *priv, |
76 | struct ieee80211_vif *vif) | 104 | struct ieee80211_vif *vif) |
77 | { | 105 | { |
@@ -97,6 +125,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | |||
97 | /* cast away the const for active_rxon in this function */ | 125 | /* cast away the const for active_rxon in this function */ |
98 | struct iwl_rxon_cmd *active = (void *)&ctx->active; | 126 | struct iwl_rxon_cmd *active = (void *)&ctx->active; |
99 | bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK); | 127 | bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK); |
128 | bool old_assoc = !!(ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK); | ||
100 | int ret; | 129 | int ret; |
101 | 130 | ||
102 | lockdep_assert_held(&priv->mutex); | 131 | lockdep_assert_held(&priv->mutex); |
@@ -176,25 +205,27 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | |||
176 | * AP station must be done after the BSSID is set to correctly | 205 | * AP station must be done after the BSSID is set to correctly |
177 | * set up filters in the device. | 206 | * set up filters in the device. |
178 | */ | 207 | */ |
179 | if (ctx->ctxid == IWL_RXON_CTX_BSS) | 208 | if ((old_assoc && new_assoc) || !new_assoc) { |
180 | ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); | 209 | if (ctx->ctxid == IWL_RXON_CTX_BSS) |
181 | else | 210 | ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); |
182 | ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); | 211 | else |
183 | if (ret) | 212 | ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); |
184 | return ret; | 213 | if (ret) |
214 | return ret; | ||
185 | 215 | ||
186 | memcpy(active, &ctx->staging, sizeof(*active)); | 216 | memcpy(active, &ctx->staging, sizeof(*active)); |
187 | 217 | ||
188 | /* | 218 | /* |
189 | * Un-assoc RXON clears the station table and WEP | 219 | * Un-assoc RXON clears the station table and WEP |
190 | * keys, so we have to restore those afterwards. | 220 | * keys, so we have to restore those afterwards. |
191 | */ | 221 | */ |
192 | iwl_clear_ucode_stations(priv, ctx); | 222 | iwl_clear_ucode_stations(priv, ctx); |
193 | iwl_restore_stations(priv, ctx); | 223 | iwl_restore_stations(priv, ctx); |
194 | ret = iwl_restore_default_wep_keys(priv, ctx); | 224 | ret = iwl_restore_default_wep_keys(priv, ctx); |
195 | if (ret) { | 225 | if (ret) { |
196 | IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); | 226 | IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); |
197 | return ret; | 227 | return ret; |
228 | } | ||
198 | } | 229 | } |
199 | 230 | ||
200 | /* RXON timing must be before associated RXON */ | 231 | /* RXON timing must be before associated RXON */ |
@@ -205,6 +236,9 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | |||
205 | } | 236 | } |
206 | 237 | ||
207 | if (new_assoc) { | 238 | if (new_assoc) { |
239 | /* QoS info may be cleared by previous un-assoc RXON */ | ||
240 | iwlagn_update_qos(priv, ctx); | ||
241 | |||
208 | /* | 242 | /* |
209 | * We'll run into this code path when beaconing is | 243 | * We'll run into this code path when beaconing is |
210 | * enabled, but then we also need to send the beacon | 244 | * enabled, but then we also need to send the beacon |
@@ -235,6 +269,8 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | |||
235 | } | 269 | } |
236 | memcpy(active, &ctx->staging, sizeof(*active)); | 270 | memcpy(active, &ctx->staging, sizeof(*active)); |
237 | 271 | ||
272 | iwl_reprogram_ap_sta(priv, ctx); | ||
273 | |||
238 | /* IBSS beacon needs to be sent after setting assoc */ | 274 | /* IBSS beacon needs to be sent after setting assoc */ |
239 | if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) | 275 | if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) |
240 | if (iwlagn_update_beacon(priv, ctx->vif)) | 276 | if (iwlagn_update_beacon(priv, ctx->vif)) |
@@ -261,34 +297,6 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | |||
261 | return 0; | 297 | return 0; |
262 | } | 298 | } |
263 | 299 | ||
264 | static void iwlagn_update_qos(struct iwl_priv *priv, | ||
265 | struct iwl_rxon_context *ctx) | ||
266 | { | ||
267 | int ret; | ||
268 | |||
269 | if (!ctx->is_active) | ||
270 | return; | ||
271 | |||
272 | ctx->qos_data.def_qos_parm.qos_flags = 0; | ||
273 | |||
274 | if (ctx->qos_data.qos_active) | ||
275 | ctx->qos_data.def_qos_parm.qos_flags |= | ||
276 | QOS_PARAM_FLG_UPDATE_EDCA_MSK; | ||
277 | |||
278 | if (ctx->ht.enabled) | ||
279 | ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; | ||
280 | |||
281 | IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", | ||
282 | ctx->qos_data.qos_active, | ||
283 | ctx->qos_data.def_qos_parm.qos_flags); | ||
284 | |||
285 | ret = iwl_send_cmd_pdu(priv, ctx->qos_cmd, | ||
286 | sizeof(struct iwl_qosparam_cmd), | ||
287 | &ctx->qos_data.def_qos_parm); | ||
288 | if (ret) | ||
289 | IWL_ERR(priv, "Failed to update QoS\n"); | ||
290 | } | ||
291 | |||
292 | int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) | 300 | int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) |
293 | { | 301 | { |
294 | struct iwl_priv *priv = hw->priv; | 302 | struct iwl_priv *priv = hw->priv; |
@@ -507,6 +515,11 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, | |||
507 | 515 | ||
508 | mutex_lock(&priv->mutex); | 516 | mutex_lock(&priv->mutex); |
509 | 517 | ||
518 | if (WARN_ON(!ctx->vif)) { | ||
519 | mutex_unlock(&priv->mutex); | ||
520 | return; | ||
521 | } | ||
522 | |||
510 | if (changes & BSS_CHANGED_BEACON_INT) | 523 | if (changes & BSS_CHANGED_BEACON_INT) |
511 | force = true; | 524 | force = true; |
512 | 525 | ||