aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2010-05-17 13:57:43 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-05-17 13:57:43 -0400
commit6fe70aae0d128339febfabc073ba4c4a03de4f45 (patch)
tree711dff90df5ca4e07b5bddf11b2819e5cf2b7a93 /net/mac80211/mlme.c
parent278554bd6579206921f5d8a523649a7a57f8850d (diff)
parent0c348d7c1422d59a86d6fb37b53d75788043e50b (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c59
1 files changed, 54 insertions, 5 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 3093e46273c3..c6c1f49cc456 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -342,7 +342,11 @@ static void ieee80211_chswitch_work(struct work_struct *work)
342 goto out; 342 goto out;
343 343
344 sdata->local->oper_channel = sdata->local->csa_channel; 344 sdata->local->oper_channel = sdata->local->csa_channel;
345 ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL); 345 if (!sdata->local->ops->channel_switch) {
346 /* call "hw_config" only if doing sw channel switch */
347 ieee80211_hw_config(sdata->local,
348 IEEE80211_CONF_CHANGE_CHANNEL);
349 }
346 350
347 /* XXX: shouldn't really modify cfg80211-owned data! */ 351 /* XXX: shouldn't really modify cfg80211-owned data! */
348 ifmgd->associated->channel = sdata->local->oper_channel; 352 ifmgd->associated->channel = sdata->local->oper_channel;
@@ -354,6 +358,29 @@ static void ieee80211_chswitch_work(struct work_struct *work)
354 mutex_unlock(&ifmgd->mtx); 358 mutex_unlock(&ifmgd->mtx);
355} 359}
356 360
361void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
362{
363 struct ieee80211_sub_if_data *sdata;
364 struct ieee80211_if_managed *ifmgd;
365
366 sdata = vif_to_sdata(vif);
367 ifmgd = &sdata->u.mgd;
368
369 trace_api_chswitch_done(sdata, success);
370 if (!success) {
371 /*
372 * If the channel switch was not successful, stay
373 * around on the old channel. We currently lack
374 * good handling of this situation, possibly we
375 * should just drop the association.
376 */
377 sdata->local->csa_channel = sdata->local->oper_channel;
378 }
379
380 ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
381}
382EXPORT_SYMBOL(ieee80211_chswitch_done);
383
357static void ieee80211_chswitch_timer(unsigned long data) 384static void ieee80211_chswitch_timer(unsigned long data)
358{ 385{
359 struct ieee80211_sub_if_data *sdata = 386 struct ieee80211_sub_if_data *sdata =
@@ -370,7 +397,8 @@ static void ieee80211_chswitch_timer(unsigned long data)
370 397
371void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, 398void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
372 struct ieee80211_channel_sw_ie *sw_elem, 399 struct ieee80211_channel_sw_ie *sw_elem,
373 struct ieee80211_bss *bss) 400 struct ieee80211_bss *bss,
401 u64 timestamp)
374{ 402{
375 struct cfg80211_bss *cbss = 403 struct cfg80211_bss *cbss =
376 container_of((void *)bss, struct cfg80211_bss, priv); 404 container_of((void *)bss, struct cfg80211_bss, priv);
@@ -398,10 +426,29 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
398 426
399 sdata->local->csa_channel = new_ch; 427 sdata->local->csa_channel = new_ch;
400 428
429 if (sdata->local->ops->channel_switch) {
430 /* use driver's channel switch callback */
431 struct ieee80211_channel_switch ch_switch;
432 memset(&ch_switch, 0, sizeof(ch_switch));
433 ch_switch.timestamp = timestamp;
434 if (sw_elem->mode) {
435 ch_switch.block_tx = true;
436 ieee80211_stop_queues_by_reason(&sdata->local->hw,
437 IEEE80211_QUEUE_STOP_REASON_CSA);
438 }
439 ch_switch.channel = new_ch;
440 ch_switch.count = sw_elem->count;
441 ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
442 drv_channel_switch(sdata->local, &ch_switch);
443 return;
444 }
445
446 /* channel switch handled in software */
401 if (sw_elem->count <= 1) { 447 if (sw_elem->count <= 1) {
402 ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); 448 ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
403 } else { 449 } else {
404 ieee80211_stop_queues_by_reason(&sdata->local->hw, 450 if (sw_elem->mode)
451 ieee80211_stop_queues_by_reason(&sdata->local->hw,
405 IEEE80211_QUEUE_STOP_REASON_CSA); 452 IEEE80211_QUEUE_STOP_REASON_CSA);
406 ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; 453 ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
407 mod_timer(&ifmgd->chswitch_timer, 454 mod_timer(&ifmgd->chswitch_timer,
@@ -1317,7 +1364,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
1317 ETH_ALEN) == 0)) { 1364 ETH_ALEN) == 0)) {
1318 struct ieee80211_channel_sw_ie *sw_elem = 1365 struct ieee80211_channel_sw_ie *sw_elem =
1319 (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; 1366 (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
1320 ieee80211_sta_process_chanswitch(sdata, sw_elem, bss); 1367 ieee80211_sta_process_chanswitch(sdata, sw_elem,
1368 bss, rx_status->mactime);
1321 } 1369 }
1322} 1370}
1323 1371
@@ -1649,7 +1697,8 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
1649 1697
1650 ieee80211_sta_process_chanswitch(sdata, 1698 ieee80211_sta_process_chanswitch(sdata,
1651 &mgmt->u.action.u.chan_switch.sw_elem, 1699 &mgmt->u.action.u.chan_switch.sw_elem,
1652 (void *)ifmgd->associated->priv); 1700 (void *)ifmgd->associated->priv,
1701 rx_status->mactime);
1653 break; 1702 break;
1654 } 1703 }
1655 mutex_unlock(&ifmgd->mtx); 1704 mutex_unlock(&ifmgd->mtx);