diff options
Diffstat (limited to 'net/mac80211/spectmgmt.c')
-rw-r--r-- | net/mac80211/spectmgmt.c | 100 |
1 files changed, 99 insertions, 1 deletions
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index f72bad636d8e..8d4ec2968f8f 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c | |||
@@ -65,7 +65,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da | |||
65 | IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED; | 65 | IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED; |
66 | msr_report->u.action.u.measurement.msr_elem.type = request_ie->type; | 66 | msr_report->u.action.u.measurement.msr_elem.type = request_ie->type; |
67 | 67 | ||
68 | ieee80211_tx_skb(sdata, skb, 0); | 68 | ieee80211_tx_skb(sdata, skb, 1); |
69 | } | 69 | } |
70 | 70 | ||
71 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 71 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
@@ -84,3 +84,101 @@ 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.sta.chswitch_work); | ||
92 | struct ieee80211_bss *bss; | ||
93 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
94 | |||
95 | if (!netif_running(sdata->dev)) | ||
96 | return; | ||
97 | |||
98 | bss = ieee80211_rx_bss_get(sdata->local, ifsta->bssid, | ||
99 | sdata->local->hw.conf.channel->center_freq, | ||
100 | ifsta->ssid, ifsta->ssid_len); | ||
101 | if (!bss) | ||
102 | goto exit; | ||
103 | |||
104 | sdata->local->oper_channel = sdata->local->csa_channel; | ||
105 | if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL)) | ||
106 | bss->freq = sdata->local->oper_channel->center_freq; | ||
107 | |||
108 | ieee80211_rx_bss_put(sdata->local, bss); | ||
109 | exit: | ||
110 | ifsta->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
111 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||
112 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
113 | } | ||
114 | |||
115 | void ieee80211_chswitch_timer(unsigned long data) | ||
116 | { | ||
117 | struct ieee80211_sub_if_data *sdata = | ||
118 | (struct ieee80211_sub_if_data *) data; | ||
119 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
120 | |||
121 | queue_work(sdata->local->hw.workqueue, &ifsta->chswitch_work); | ||
122 | } | ||
123 | |||
124 | void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, | ||
125 | struct ieee80211_channel_sw_ie *sw_elem, | ||
126 | struct ieee80211_bss *bss) | ||
127 | { | ||
128 | struct ieee80211_channel *new_ch; | ||
129 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
130 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); | ||
131 | |||
132 | /* FIXME: Handle ADHOC later */ | ||
133 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
134 | return; | ||
135 | |||
136 | if (ifsta->state != IEEE80211_STA_MLME_ASSOCIATED) | ||
137 | return; | ||
138 | |||
139 | if (sdata->local->sw_scanning || sdata->local->hw_scanning) | ||
140 | return; | ||
141 | |||
142 | /* Disregard subsequent beacons if we are already running a timer | ||
143 | processing a CSA */ | ||
144 | |||
145 | if (ifsta->flags & IEEE80211_STA_CSA_RECEIVED) | ||
146 | return; | ||
147 | |||
148 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | ||
149 | if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) | ||
150 | return; | ||
151 | |||
152 | sdata->local->csa_channel = new_ch; | ||
153 | |||
154 | if (sw_elem->count <= 1) { | ||
155 | queue_work(sdata->local->hw.workqueue, &ifsta->chswitch_work); | ||
156 | } else { | ||
157 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||
158 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
159 | ifsta->flags |= IEEE80211_STA_CSA_RECEIVED; | ||
160 | mod_timer(&ifsta->chswitch_timer, | ||
161 | jiffies + msecs_to_jiffies(sw_elem->count * bss->beacon_int)); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | ||
166 | u16 capab_info, u8 *pwr_constr_elem, | ||
167 | u8 pwr_constr_elem_len) | ||
168 | { | ||
169 | struct ieee80211_conf *conf = &sdata->local->hw.conf; | ||
170 | |||
171 | if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT)) | ||
172 | return; | ||
173 | |||
174 | /* Power constraint IE length should be 1 octet */ | ||
175 | if (pwr_constr_elem_len != 1) | ||
176 | return; | ||
177 | |||
178 | if ((*pwr_constr_elem <= conf->channel->max_power) && | ||
179 | (*pwr_constr_elem != sdata->local->power_constr_level)) { | ||
180 | sdata->local->power_constr_level = *pwr_constr_elem; | ||
181 | ieee80211_hw_config(sdata->local, 0); | ||
182 | } | ||
183 | } | ||
184 | |||