aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-05-15 05:52:31 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-05-20 14:46:25 -0400
commitcc32abd494c0a8f76f2638e3f3a76e01c68bc9ea (patch)
tree02e6870c634e637c7082596f4e3d23804285c8de /net/mac80211/mlme.c
parent9f26a952210e44691f784b77bf1f83a500d63f58 (diff)
mac80211: move channel switch code
The channel switch code is currently in the spectrum management file, where arguably it belongs. However, it is for managed mode only and uses the structures for that mode only so having it in a more generic file can be confusing. Additionally, my next patch gets simpler with the code here. When/if we ever implement this for IBSS or mesh then we will need to rework the structures it uses anyway at which point we could move the code back. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c99
1 files changed, 98 insertions, 1 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 47bc3030ca8..41f3c1f98cc 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -486,6 +486,103 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
486 ieee80211_tx_skb(sdata, skb, 0); 486 ieee80211_tx_skb(sdata, skb, 0);
487} 487}
488 488
489/* spectrum management related things */
490static void ieee80211_chswitch_work(struct work_struct *work)
491{
492 struct ieee80211_sub_if_data *sdata =
493 container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
494 struct ieee80211_bss *bss;
495 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
496
497 if (!netif_running(sdata->dev))
498 return;
499
500 bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid,
501 sdata->local->hw.conf.channel->center_freq,
502 ifmgd->ssid, ifmgd->ssid_len);
503 if (!bss)
504 goto exit;
505
506 sdata->local->oper_channel = sdata->local->csa_channel;
507 /* XXX: shouldn't really modify cfg80211-owned data! */
508 if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL))
509 bss->cbss.channel = sdata->local->oper_channel;
510
511 ieee80211_rx_bss_put(sdata->local, bss);
512exit:
513 ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
514 ieee80211_wake_queues_by_reason(&sdata->local->hw,
515 IEEE80211_QUEUE_STOP_REASON_CSA);
516}
517
518static void ieee80211_chswitch_timer(unsigned long data)
519{
520 struct ieee80211_sub_if_data *sdata =
521 (struct ieee80211_sub_if_data *) data;
522 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
523
524 queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
525}
526
527void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
528 struct ieee80211_channel_sw_ie *sw_elem,
529 struct ieee80211_bss *bss)
530{
531 struct ieee80211_channel *new_ch;
532 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
533 int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num);
534
535 if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED)
536 return;
537
538 if (sdata->local->sw_scanning || sdata->local->hw_scanning)
539 return;
540
541 /* Disregard subsequent beacons if we are already running a timer
542 processing a CSA */
543
544 if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
545 return;
546
547 new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
548 if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED)
549 return;
550
551 sdata->local->csa_channel = new_ch;
552
553 if (sw_elem->count <= 1) {
554 queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
555 } else {
556 ieee80211_stop_queues_by_reason(&sdata->local->hw,
557 IEEE80211_QUEUE_STOP_REASON_CSA);
558 ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
559 mod_timer(&ifmgd->chswitch_timer,
560 jiffies +
561 msecs_to_jiffies(sw_elem->count *
562 bss->cbss.beacon_interval));
563 }
564}
565
566static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
567 u16 capab_info, u8 *pwr_constr_elem,
568 u8 pwr_constr_elem_len)
569{
570 struct ieee80211_conf *conf = &sdata->local->hw.conf;
571
572 if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT))
573 return;
574
575 /* Power constraint IE length should be 1 octet */
576 if (pwr_constr_elem_len != 1)
577 return;
578
579 if ((*pwr_constr_elem <= conf->channel->max_power) &&
580 (*pwr_constr_elem != sdata->local->power_constr_level)) {
581 sdata->local->power_constr_level = *pwr_constr_elem;
582 ieee80211_hw_config(sdata->local, 0);
583 }
584}
585
489/* powersave */ 586/* powersave */
490static void ieee80211_enable_ps(struct ieee80211_local *local, 587static void ieee80211_enable_ps(struct ieee80211_local *local,
491 struct ieee80211_sub_if_data *sdata) 588 struct ieee80211_sub_if_data *sdata)
@@ -1736,7 +1833,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
1736 (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) { 1833 (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) {
1737 struct ieee80211_channel_sw_ie *sw_elem = 1834 struct ieee80211_channel_sw_ie *sw_elem =
1738 (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; 1835 (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
1739 ieee80211_process_chanswitch(sdata, sw_elem, bss); 1836 ieee80211_sta_process_chanswitch(sdata, sw_elem, bss);
1740 } 1837 }
1741 1838
1742 ieee80211_rx_bss_put(local, bss); 1839 ieee80211_rx_bss_put(local, bss);