aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
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);