diff options
-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 | |||