aboutsummaryrefslogtreecommitdiffstats
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
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>
-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