diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-05-15 05:52:31 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-05-20 14:46:25 -0400 |
commit | cc32abd494c0a8f76f2638e3f3a76e01c68bc9ea (patch) | |
tree | 02e6870c634e637c7082596f4e3d23804285c8de | |
parent | 9f26a952210e44691f784b77bf1f83a500d63f58 (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.h | 11 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 99 | ||||
-rw-r--r-- | net/mac80211/rx.c | 5 | ||||
-rw-r--r-- | net/mac80211/spectmgmt.c | 101 |
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, | |||
934 | void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); | 934 | void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); |
935 | int ieee80211_max_network_latency(struct notifier_block *nb, | 935 | int ieee80211_max_network_latency(struct notifier_block *nb, |
936 | unsigned long data, void *dummy); | 936 | unsigned long data, void *dummy); |
937 | void 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 */ |
939 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); | 942 | void 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, | |||
1031 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1034 | void 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); |
1034 | void ieee80211_chswitch_timer(unsigned long data); | ||
1035 | void ieee80211_chswitch_work(struct work_struct *work); | ||
1036 | void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, | ||
1037 | struct ieee80211_channel_sw_ie *sw_elem, | ||
1038 | struct ieee80211_bss *bss); | ||
1039 | void 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 */ |
1044 | int ieee80211_reconfig(struct ieee80211_local *local); | 1039 | int 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 */ | ||
490 | static 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); | ||
512 | exit: | ||
513 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
514 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||
515 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
516 | } | ||
517 | |||
518 | static 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 | |||
527 | void 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 | |||
566 | static 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 */ |
490 | static void ieee80211_enable_ps(struct ieee80211_local *local, | 587 | static 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 | |||
88 | void 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); | ||
110 | exit: | ||
111 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
112 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||
113 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
114 | } | ||
115 | |||
116 | void 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 | |||
125 | void 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 | |||
168 | void 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 | |||