diff options
author | John W. Linville <linville@tuxdriver.com> | 2010-05-17 13:57:43 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-05-17 13:57:43 -0400 |
commit | 6fe70aae0d128339febfabc073ba4c4a03de4f45 (patch) | |
tree | 711dff90df5ca4e07b5bddf11b2819e5cf2b7a93 /net/mac80211/mlme.c | |
parent | 278554bd6579206921f5d8a523649a7a57f8850d (diff) | |
parent | 0c348d7c1422d59a86d6fb37b53d75788043e50b (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.c | 59 |
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 | ||
361 | void 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 | } | ||
382 | EXPORT_SYMBOL(ieee80211_chswitch_done); | ||
383 | |||
357 | static void ieee80211_chswitch_timer(unsigned long data) | 384 | static 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 | ||
371 | void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 398 | void 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); |