aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/ieee80211_i.h11
-rw-r--r--net/mac80211/mlme.c99
-rw-r--r--net/mac80211/rx.c5
-rw-r--r--net/mac80211/spectmgmt.c101
4 files changed, 105 insertions, 111 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3241e76eece7..be9446551cf6 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -934,6 +934,9 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
934void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); 934void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
935int ieee80211_max_network_latency(struct notifier_block *nb, 935int ieee80211_max_network_latency(struct notifier_block *nb,
936 unsigned long data, void *dummy); 936 unsigned long data, void *dummy);
937void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
938 struct ieee80211_channel_sw_ie *sw_elem,
939 struct ieee80211_bss *bss);
937 940
938/* IBSS code */ 941/* IBSS code */
939void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); 942void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
@@ -1031,14 +1034,6 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
1031void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, 1034void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
1032 struct ieee80211_mgmt *mgmt, 1035 struct ieee80211_mgmt *mgmt,
1033 size_t len); 1036 size_t len);
1034void ieee80211_chswitch_timer(unsigned long data);
1035void ieee80211_chswitch_work(struct work_struct *work);
1036void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1037 struct ieee80211_channel_sw_ie *sw_elem,
1038 struct ieee80211_bss *bss);
1039void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
1040 u16 capab_info, u8 *pwr_constr_elem,
1041 u8 pwr_constr_elem_len);
1042 1037
1043/* Suspend/resume and hw reconfiguration */ 1038/* Suspend/resume and hw reconfiguration */
1044int ieee80211_reconfig(struct ieee80211_local *local); 1039int ieee80211_reconfig(struct ieee80211_local *local);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 47bc3030ca87..41f3c1f98cc3 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);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index f962bd1b16e2..f3a041cc5dcf 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1846,6 +1846,9 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1846 sizeof(mgmt->u.action.u.chan_switch))) 1846 sizeof(mgmt->u.action.u.chan_switch)))
1847 return RX_DROP_MONITOR; 1847 return RX_DROP_MONITOR;
1848 1848
1849 if (sdata->vif.type != NL80211_IFTYPE_STATION)
1850 return RX_DROP_MONITOR;
1851
1849 if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) 1852 if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
1850 return RX_DROP_MONITOR; 1853 return RX_DROP_MONITOR;
1851 1854
@@ -1856,7 +1859,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1856 if (!bss) 1859 if (!bss)
1857 return RX_DROP_MONITOR; 1860 return RX_DROP_MONITOR;
1858 1861
1859 ieee80211_process_chanswitch(sdata, 1862 ieee80211_sta_process_chanswitch(sdata,
1860 &mgmt->u.action.u.chan_switch.sw_elem, bss); 1863 &mgmt->u.action.u.chan_switch.sw_elem, bss);
1861 ieee80211_rx_bss_put(local, bss); 1864 ieee80211_rx_bss_put(local, bss);
1862 break; 1865 break;
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 48bf78e7fa7a..68953033403d 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -84,104 +84,3 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
84 mgmt->sa, mgmt->bssid, 84 mgmt->sa, mgmt->bssid,
85 mgmt->u.action.u.measurement.dialog_token); 85 mgmt->u.action.u.measurement.dialog_token);
86} 86}
87
88void ieee80211_chswitch_work(struct work_struct *work)
89{
90 struct ieee80211_sub_if_data *sdata =
91 container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
92 struct ieee80211_bss *bss;
93 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
94
95 if (!netif_running(sdata->dev))
96 return;
97
98 bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid,
99 sdata->local->hw.conf.channel->center_freq,
100 ifmgd->ssid, ifmgd->ssid_len);
101 if (!bss)
102 goto exit;
103
104 sdata->local->oper_channel = sdata->local->csa_channel;
105 /* XXX: shouldn't really modify cfg80211-owned data! */
106 if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL))
107 bss->cbss.channel = sdata->local->oper_channel;
108
109 ieee80211_rx_bss_put(sdata->local, bss);
110exit:
111 ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
112 ieee80211_wake_queues_by_reason(&sdata->local->hw,
113 IEEE80211_QUEUE_STOP_REASON_CSA);
114}
115
116void ieee80211_chswitch_timer(unsigned long data)
117{
118 struct ieee80211_sub_if_data *sdata =
119 (struct ieee80211_sub_if_data *) data;
120 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
121
122 queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
123}
124
125void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata,
126 struct ieee80211_channel_sw_ie *sw_elem,
127 struct ieee80211_bss *bss)
128{
129 struct ieee80211_channel *new_ch;
130 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
131 int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num);
132
133 /* FIXME: Handle ADHOC later */
134 if (sdata->vif.type != NL80211_IFTYPE_STATION)
135 return;
136
137 if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED)
138 return;
139
140 if (sdata->local->sw_scanning || sdata->local->hw_scanning)
141 return;
142
143 /* Disregard subsequent beacons if we are already running a timer
144 processing a CSA */
145
146 if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
147 return;
148
149 new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
150 if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED)
151 return;
152
153 sdata->local->csa_channel = new_ch;
154
155 if (sw_elem->count <= 1) {
156 queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
157 } else {
158 ieee80211_stop_queues_by_reason(&sdata->local->hw,
159 IEEE80211_QUEUE_STOP_REASON_CSA);
160 ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
161 mod_timer(&ifmgd->chswitch_timer,
162 jiffies +
163 msecs_to_jiffies(sw_elem->count *
164 bss->cbss.beacon_interval));
165 }
166}
167
168void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
169 u16 capab_info, u8 *pwr_constr_elem,
170 u8 pwr_constr_elem_len)
171{
172 struct ieee80211_conf *conf = &sdata->local->hw.conf;
173
174 if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT))
175 return;
176
177 /* Power constraint IE length should be 1 octet */
178 if (pwr_constr_elem_len != 1)
179 return;
180
181 if ((*pwr_constr_elem <= conf->channel->max_power) &&
182 (*pwr_constr_elem != sdata->local->power_constr_level)) {
183 sdata->local->power_constr_level = *pwr_constr_elem;
184 ieee80211_hw_config(sdata->local, 0);
185 }
186}
187