diff options
author | David S. Miller <davem@davemloft.net> | 2010-01-19 14:43:42 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-01-19 14:43:42 -0500 |
commit | 6373464288cab09bc641be301d8d30fc9f64ba71 (patch) | |
tree | c1bc92dc630aa15da2e12bc0d09c92169817a702 /net | |
parent | 6d955180b2f9ccff444df06265160868cabb289a (diff) | |
parent | 730dd70549e0ec755dd55615ba5cfc38a482a947 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Conflicts:
drivers/net/wireless/iwlwifi/iwl-core.h
Diffstat (limited to 'net')
30 files changed, 1390 insertions, 304 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index ceda36618d3c..718fbcff84d2 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -179,7 +179,8 @@ static void sta_addba_resp_timer_expired(unsigned long data) | |||
179 | 179 | ||
180 | /* check if the TID waits for addBA response */ | 180 | /* check if the TID waits for addBA response */ |
181 | spin_lock_bh(&sta->lock); | 181 | spin_lock_bh(&sta->lock); |
182 | if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK)) != | 182 | if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK | |
183 | HT_AGG_STATE_REQ_STOP_BA_MSK)) != | ||
183 | HT_ADDBA_REQUESTED_MSK) { | 184 | HT_ADDBA_REQUESTED_MSK) { |
184 | spin_unlock_bh(&sta->lock); | 185 | spin_unlock_bh(&sta->lock); |
185 | *state = HT_AGG_STATE_IDLE; | 186 | *state = HT_AGG_STATE_IDLE; |
@@ -301,7 +302,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
301 | * call back right away, it must see that the flow has begun */ | 302 | * call back right away, it must see that the flow has begun */ |
302 | *state |= HT_ADDBA_REQUESTED_MSK; | 303 | *state |= HT_ADDBA_REQUESTED_MSK; |
303 | 304 | ||
304 | start_seq_num = sta->tid_seq[tid]; | 305 | start_seq_num = sta->tid_seq[tid] >> 4; |
305 | 306 | ||
306 | ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, | 307 | ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, |
307 | pubsta, tid, &start_seq_num); | 308 | pubsta, tid, &start_seq_num); |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 2e5e841e9b7b..b0102c538b30 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -148,7 +148,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
148 | rcu_read_lock(); | 148 | rcu_read_lock(); |
149 | 149 | ||
150 | if (mac_addr) { | 150 | if (mac_addr) { |
151 | sta = sta_info_get(sdata, mac_addr); | 151 | sta = sta_info_get_bss(sdata, mac_addr); |
152 | if (!sta) { | 152 | if (!sta) { |
153 | ieee80211_key_free(key); | 153 | ieee80211_key_free(key); |
154 | err = -ENOENT; | 154 | err = -ENOENT; |
@@ -179,7 +179,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
179 | if (mac_addr) { | 179 | if (mac_addr) { |
180 | ret = -ENOENT; | 180 | ret = -ENOENT; |
181 | 181 | ||
182 | sta = sta_info_get(sdata, mac_addr); | 182 | sta = sta_info_get_bss(sdata, mac_addr); |
183 | if (!sta) | 183 | if (!sta) |
184 | goto out_unlock; | 184 | goto out_unlock; |
185 | 185 | ||
@@ -226,7 +226,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
226 | rcu_read_lock(); | 226 | rcu_read_lock(); |
227 | 227 | ||
228 | if (mac_addr) { | 228 | if (mac_addr) { |
229 | sta = sta_info_get(sdata, mac_addr); | 229 | sta = sta_info_get_bss(sdata, mac_addr); |
230 | if (!sta) | 230 | if (!sta) |
231 | goto out; | 231 | goto out; |
232 | 232 | ||
@@ -419,7 +419,7 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | |||
419 | 419 | ||
420 | rcu_read_lock(); | 420 | rcu_read_lock(); |
421 | 421 | ||
422 | sta = sta_info_get(sdata, mac); | 422 | sta = sta_info_get_bss(sdata, mac); |
423 | if (sta) { | 423 | if (sta) { |
424 | ret = 0; | 424 | ret = 0; |
425 | sta_set_sinfo(sta, sinfo); | 425 | sta_set_sinfo(sta, sinfo); |
@@ -775,7 +775,7 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
775 | if (mac) { | 775 | if (mac) { |
776 | rcu_read_lock(); | 776 | rcu_read_lock(); |
777 | 777 | ||
778 | sta = sta_info_get(sdata, mac); | 778 | sta = sta_info_get_bss(sdata, mac); |
779 | if (!sta) { | 779 | if (!sta) { |
780 | rcu_read_unlock(); | 780 | rcu_read_unlock(); |
781 | return -ENOENT; | 781 | return -ENOENT; |
@@ -803,7 +803,7 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
803 | 803 | ||
804 | rcu_read_lock(); | 804 | rcu_read_lock(); |
805 | 805 | ||
806 | sta = sta_info_get(sdata, mac); | 806 | sta = sta_info_get_bss(sdata, mac); |
807 | if (!sta) { | 807 | if (!sta) { |
808 | rcu_read_unlock(); | 808 | rcu_read_unlock(); |
809 | return -ENOENT; | 809 | return -ENOENT; |
@@ -1085,6 +1085,13 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
1085 | params->use_short_preamble; | 1085 | params->use_short_preamble; |
1086 | changed |= BSS_CHANGED_ERP_PREAMBLE; | 1086 | changed |= BSS_CHANGED_ERP_PREAMBLE; |
1087 | } | 1087 | } |
1088 | |||
1089 | if (!sdata->vif.bss_conf.use_short_slot && | ||
1090 | sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) { | ||
1091 | sdata->vif.bss_conf.use_short_slot = true; | ||
1092 | changed |= BSS_CHANGED_ERP_SLOT; | ||
1093 | } | ||
1094 | |||
1088 | if (params->use_short_slot_time >= 0) { | 1095 | if (params->use_short_slot_time >= 0) { |
1089 | sdata->vif.bss_conf.use_short_slot = | 1096 | sdata->vif.bss_conf.use_short_slot = |
1090 | params->use_short_slot_time; | 1097 | params->use_short_slot_time; |
@@ -1128,6 +1135,13 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, | |||
1128 | p.cw_max = params->cwmax; | 1135 | p.cw_max = params->cwmax; |
1129 | p.cw_min = params->cwmin; | 1136 | p.cw_min = params->cwmin; |
1130 | p.txop = params->txop; | 1137 | p.txop = params->txop; |
1138 | |||
1139 | /* | ||
1140 | * Setting tx queue params disables u-apsd because it's only | ||
1141 | * called in master mode. | ||
1142 | */ | ||
1143 | p.uapsd = false; | ||
1144 | |||
1131 | if (drv_conf_tx(local, params->queue, &p)) { | 1145 | if (drv_conf_tx(local, params->queue, &p)) { |
1132 | printk(KERN_DEBUG "%s: failed to set TX queue " | 1146 | printk(KERN_DEBUG "%s: failed to set TX queue " |
1133 | "parameters for queue %d\n", | 1147 | "parameters for queue %d\n", |
@@ -1230,6 +1244,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
1230 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1244 | struct ieee80211_local *local = wiphy_priv(wiphy); |
1231 | int err; | 1245 | int err; |
1232 | 1246 | ||
1247 | if (changed & WIPHY_PARAM_COVERAGE_CLASS) { | ||
1248 | err = drv_set_coverage_class(local, wiphy->coverage_class); | ||
1249 | |||
1250 | if (err) | ||
1251 | return err; | ||
1252 | } | ||
1253 | |||
1233 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { | 1254 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { |
1234 | err = drv_set_rts_threshold(local, wiphy->rts_threshold); | 1255 | err = drv_set_rts_threshold(local, wiphy->rts_threshold); |
1235 | 1256 | ||
@@ -1399,8 +1420,6 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
1399 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1420 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1400 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1421 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1401 | int i; | 1422 | int i; |
1402 | u32 target_rate; | ||
1403 | struct ieee80211_supported_band *sband; | ||
1404 | 1423 | ||
1405 | /* | 1424 | /* |
1406 | * This _could_ be supported by providing a hook for | 1425 | * This _could_ be supported by providing a hook for |
@@ -1410,35 +1429,11 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
1410 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) | 1429 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) |
1411 | return -EOPNOTSUPP; | 1430 | return -EOPNOTSUPP; |
1412 | 1431 | ||
1413 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1414 | |||
1415 | /* | ||
1416 | * target_rate = -1, rate->fixed = 0 means auto only, so use all rates | ||
1417 | * target_rate = X, rate->fixed = 1 means only rate X | ||
1418 | * target_rate = X, rate->fixed = 0 means all rates <= X | ||
1419 | */ | ||
1420 | sdata->max_ratectrl_rateidx = -1; | ||
1421 | sdata->force_unicast_rateidx = -1; | ||
1422 | |||
1423 | if (mask->fixed) | ||
1424 | target_rate = mask->fixed / 100; | ||
1425 | else if (mask->maxrate) | ||
1426 | target_rate = mask->maxrate / 100; | ||
1427 | else | ||
1428 | return 0; | ||
1429 | |||
1430 | for (i = 0; i< sband->n_bitrates; i++) { | ||
1431 | if (target_rate != sband->bitrates[i].bitrate) | ||
1432 | continue; | ||
1433 | 1432 | ||
1434 | /* requested bitrate found */ | 1433 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) |
1435 | sdata->max_ratectrl_rateidx = i; | 1434 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; |
1436 | if (mask->fixed) | ||
1437 | sdata->force_unicast_rateidx = i; | ||
1438 | return 0; | ||
1439 | } | ||
1440 | 1435 | ||
1441 | return -EINVAL; | 1436 | return 0; |
1442 | } | 1437 | } |
1443 | 1438 | ||
1444 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, | 1439 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index e4b54093d41b..b3bc32b62a5a 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -158,6 +158,98 @@ static const struct file_operations noack_ops = { | |||
158 | .open = mac80211_open_file_generic | 158 | .open = mac80211_open_file_generic |
159 | }; | 159 | }; |
160 | 160 | ||
161 | static ssize_t uapsd_queues_read(struct file *file, char __user *user_buf, | ||
162 | size_t count, loff_t *ppos) | ||
163 | { | ||
164 | struct ieee80211_local *local = file->private_data; | ||
165 | int res; | ||
166 | char buf[10]; | ||
167 | |||
168 | res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_queues); | ||
169 | |||
170 | return simple_read_from_buffer(user_buf, count, ppos, buf, res); | ||
171 | } | ||
172 | |||
173 | static ssize_t uapsd_queues_write(struct file *file, | ||
174 | const char __user *user_buf, | ||
175 | size_t count, loff_t *ppos) | ||
176 | { | ||
177 | struct ieee80211_local *local = file->private_data; | ||
178 | unsigned long val; | ||
179 | char buf[10]; | ||
180 | size_t len; | ||
181 | int ret; | ||
182 | |||
183 | len = min(count, sizeof(buf) - 1); | ||
184 | if (copy_from_user(buf, user_buf, len)) | ||
185 | return -EFAULT; | ||
186 | buf[len] = '\0'; | ||
187 | |||
188 | ret = strict_strtoul(buf, 0, &val); | ||
189 | |||
190 | if (ret) | ||
191 | return -EINVAL; | ||
192 | |||
193 | if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) | ||
194 | return -ERANGE; | ||
195 | |||
196 | local->uapsd_queues = val; | ||
197 | |||
198 | return count; | ||
199 | } | ||
200 | |||
201 | static const struct file_operations uapsd_queues_ops = { | ||
202 | .read = uapsd_queues_read, | ||
203 | .write = uapsd_queues_write, | ||
204 | .open = mac80211_open_file_generic | ||
205 | }; | ||
206 | |||
207 | static ssize_t uapsd_max_sp_len_read(struct file *file, char __user *user_buf, | ||
208 | size_t count, loff_t *ppos) | ||
209 | { | ||
210 | struct ieee80211_local *local = file->private_data; | ||
211 | int res; | ||
212 | char buf[10]; | ||
213 | |||
214 | res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_max_sp_len); | ||
215 | |||
216 | return simple_read_from_buffer(user_buf, count, ppos, buf, res); | ||
217 | } | ||
218 | |||
219 | static ssize_t uapsd_max_sp_len_write(struct file *file, | ||
220 | const char __user *user_buf, | ||
221 | size_t count, loff_t *ppos) | ||
222 | { | ||
223 | struct ieee80211_local *local = file->private_data; | ||
224 | unsigned long val; | ||
225 | char buf[10]; | ||
226 | size_t len; | ||
227 | int ret; | ||
228 | |||
229 | len = min(count, sizeof(buf) - 1); | ||
230 | if (copy_from_user(buf, user_buf, len)) | ||
231 | return -EFAULT; | ||
232 | buf[len] = '\0'; | ||
233 | |||
234 | ret = strict_strtoul(buf, 0, &val); | ||
235 | |||
236 | if (ret) | ||
237 | return -EINVAL; | ||
238 | |||
239 | if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) | ||
240 | return -ERANGE; | ||
241 | |||
242 | local->uapsd_max_sp_len = val; | ||
243 | |||
244 | return count; | ||
245 | } | ||
246 | |||
247 | static const struct file_operations uapsd_max_sp_len_ops = { | ||
248 | .read = uapsd_max_sp_len_read, | ||
249 | .write = uapsd_max_sp_len_write, | ||
250 | .open = mac80211_open_file_generic | ||
251 | }; | ||
252 | |||
161 | static ssize_t queues_read(struct file *file, char __user *user_buf, | 253 | static ssize_t queues_read(struct file *file, char __user *user_buf, |
162 | size_t count, loff_t *ppos) | 254 | size_t count, loff_t *ppos) |
163 | { | 255 | { |
@@ -314,6 +406,8 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
314 | DEBUGFS_ADD(queues); | 406 | DEBUGFS_ADD(queues); |
315 | DEBUGFS_ADD_MODE(reset, 0200); | 407 | DEBUGFS_ADD_MODE(reset, 0200); |
316 | DEBUGFS_ADD(noack); | 408 | DEBUGFS_ADD(noack); |
409 | DEBUGFS_ADD(uapsd_queues); | ||
410 | DEBUGFS_ADD(uapsd_max_sp_len); | ||
317 | 411 | ||
318 | statsd = debugfs_create_dir("statistics", phyd); | 412 | statsd = debugfs_create_dir("statistics", phyd); |
319 | 413 | ||
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 59f6e3bcbd09..9affe2cd185f 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -127,8 +127,10 @@ __IEEE80211_IF_FILE(name, ieee80211_if_write_##name) | |||
127 | 127 | ||
128 | /* common attributes */ | 128 | /* common attributes */ |
129 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); | 129 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); |
130 | IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); | 130 | IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ], |
131 | IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); | 131 | HEX); |
132 | IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ], | ||
133 | HEX); | ||
132 | 134 | ||
133 | /* STA attributes */ | 135 | /* STA attributes */ |
134 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); | 136 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); |
@@ -253,7 +255,7 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode, | |||
253 | #endif | 255 | #endif |
254 | 256 | ||
255 | 257 | ||
256 | #define DEBUGFS_ADD(name, type) \ | 258 | #define DEBUGFS_ADD(name) \ |
257 | debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ | 259 | debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ |
258 | sdata, &name##_ops); | 260 | sdata, &name##_ops); |
259 | 261 | ||
@@ -263,40 +265,40 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode, | |||
263 | 265 | ||
264 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) | 266 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) |
265 | { | 267 | { |
266 | DEBUGFS_ADD(drop_unencrypted, sta); | 268 | DEBUGFS_ADD(drop_unencrypted); |
267 | DEBUGFS_ADD(force_unicast_rateidx, sta); | 269 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
268 | DEBUGFS_ADD(max_ratectrl_rateidx, sta); | 270 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
269 | 271 | ||
270 | DEBUGFS_ADD(bssid, sta); | 272 | DEBUGFS_ADD(bssid); |
271 | DEBUGFS_ADD(aid, sta); | 273 | DEBUGFS_ADD(aid); |
272 | DEBUGFS_ADD_MODE(smps, 0600); | 274 | DEBUGFS_ADD_MODE(smps, 0600); |
273 | } | 275 | } |
274 | 276 | ||
275 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) | 277 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) |
276 | { | 278 | { |
277 | DEBUGFS_ADD(drop_unencrypted, ap); | 279 | DEBUGFS_ADD(drop_unencrypted); |
278 | DEBUGFS_ADD(force_unicast_rateidx, ap); | 280 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
279 | DEBUGFS_ADD(max_ratectrl_rateidx, ap); | 281 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
280 | 282 | ||
281 | DEBUGFS_ADD(num_sta_ps, ap); | 283 | DEBUGFS_ADD(num_sta_ps); |
282 | DEBUGFS_ADD(dtim_count, ap); | 284 | DEBUGFS_ADD(dtim_count); |
283 | DEBUGFS_ADD(num_buffered_multicast, ap); | 285 | DEBUGFS_ADD(num_buffered_multicast); |
284 | } | 286 | } |
285 | 287 | ||
286 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) | 288 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) |
287 | { | 289 | { |
288 | DEBUGFS_ADD(drop_unencrypted, wds); | 290 | DEBUGFS_ADD(drop_unencrypted); |
289 | DEBUGFS_ADD(force_unicast_rateidx, wds); | 291 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
290 | DEBUGFS_ADD(max_ratectrl_rateidx, wds); | 292 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
291 | 293 | ||
292 | DEBUGFS_ADD(peer, wds); | 294 | DEBUGFS_ADD(peer); |
293 | } | 295 | } |
294 | 296 | ||
295 | static void add_vlan_files(struct ieee80211_sub_if_data *sdata) | 297 | static void add_vlan_files(struct ieee80211_sub_if_data *sdata) |
296 | { | 298 | { |
297 | DEBUGFS_ADD(drop_unencrypted, vlan); | 299 | DEBUGFS_ADD(drop_unencrypted); |
298 | DEBUGFS_ADD(force_unicast_rateidx, vlan); | 300 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
299 | DEBUGFS_ADD(max_ratectrl_rateidx, vlan); | 301 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
300 | } | 302 | } |
301 | 303 | ||
302 | static void add_monitor_files(struct ieee80211_sub_if_data *sdata) | 304 | static void add_monitor_files(struct ieee80211_sub_if_data *sdata) |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 8757ea73d544..de91d39e0276 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -214,6 +214,21 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local, | |||
214 | return ret; | 214 | return ret; |
215 | } | 215 | } |
216 | 216 | ||
217 | static inline int drv_set_coverage_class(struct ieee80211_local *local, | ||
218 | u8 value) | ||
219 | { | ||
220 | int ret = 0; | ||
221 | might_sleep(); | ||
222 | |||
223 | if (local->ops->set_coverage_class) | ||
224 | local->ops->set_coverage_class(&local->hw, value); | ||
225 | else | ||
226 | ret = -EOPNOTSUPP; | ||
227 | |||
228 | trace_drv_set_coverage_class(local, value, ret); | ||
229 | return ret; | ||
230 | } | ||
231 | |||
217 | static inline void drv_sta_notify(struct ieee80211_local *local, | 232 | static inline void drv_sta_notify(struct ieee80211_local *local, |
218 | struct ieee80211_sub_if_data *sdata, | 233 | struct ieee80211_sub_if_data *sdata, |
219 | enum sta_notify_cmd cmd, | 234 | enum sta_notify_cmd cmd, |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 977cc7528bc6..0ea258123b8e 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -491,6 +491,29 @@ TRACE_EVENT(drv_set_rts_threshold, | |||
491 | ) | 491 | ) |
492 | ); | 492 | ); |
493 | 493 | ||
494 | TRACE_EVENT(drv_set_coverage_class, | ||
495 | TP_PROTO(struct ieee80211_local *local, u8 value, int ret), | ||
496 | |||
497 | TP_ARGS(local, value, ret), | ||
498 | |||
499 | TP_STRUCT__entry( | ||
500 | LOCAL_ENTRY | ||
501 | __field(u8, value) | ||
502 | __field(int, ret) | ||
503 | ), | ||
504 | |||
505 | TP_fast_assign( | ||
506 | LOCAL_ASSIGN; | ||
507 | __entry->ret = ret; | ||
508 | __entry->value = value; | ||
509 | ), | ||
510 | |||
511 | TP_printk( | ||
512 | LOCAL_PR_FMT " value:%d ret:%d", | ||
513 | LOCAL_PR_ARG, __entry->value, __entry->ret | ||
514 | ) | ||
515 | ); | ||
516 | |||
494 | TRACE_EVENT(drv_sta_notify, | 517 | TRACE_EVENT(drv_sta_notify, |
495 | TP_PROTO(struct ieee80211_local *local, | 518 | TP_PROTO(struct ieee80211_local *local, |
496 | struct ieee80211_sub_if_data *sdata, | 519 | struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a27921ee6e63..c18f576f1848 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -58,6 +58,15 @@ struct ieee80211_local; | |||
58 | 58 | ||
59 | #define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024)) | 59 | #define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024)) |
60 | 60 | ||
61 | #define IEEE80211_DEFAULT_UAPSD_QUEUES \ | ||
62 | (IEEE80211_WMM_IE_STA_QOSINFO_AC_BK | \ | ||
63 | IEEE80211_WMM_IE_STA_QOSINFO_AC_BE | \ | ||
64 | IEEE80211_WMM_IE_STA_QOSINFO_AC_VI | \ | ||
65 | IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) | ||
66 | |||
67 | #define IEEE80211_DEFAULT_MAX_SP_LEN \ | ||
68 | IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL | ||
69 | |||
61 | struct ieee80211_fragment_entry { | 70 | struct ieee80211_fragment_entry { |
62 | unsigned long first_frag_time; | 71 | unsigned long first_frag_time; |
63 | unsigned int seq; | 72 | unsigned int seq; |
@@ -78,6 +87,7 @@ struct ieee80211_bss { | |||
78 | u8 dtim_period; | 87 | u8 dtim_period; |
79 | 88 | ||
80 | bool wmm_used; | 89 | bool wmm_used; |
90 | bool uapsd_supported; | ||
81 | 91 | ||
82 | unsigned long last_probe_resp; | 92 | unsigned long last_probe_resp; |
83 | 93 | ||
@@ -285,7 +295,7 @@ struct ieee80211_work { | |||
285 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 295 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
286 | u8 ssid_len; | 296 | u8 ssid_len; |
287 | u8 supp_rates_len; | 297 | u8 supp_rates_len; |
288 | bool wmm_used, use_11n; | 298 | bool wmm_used, use_11n, uapsd_used; |
289 | } assoc; | 299 | } assoc; |
290 | struct { | 300 | struct { |
291 | u32 duration; | 301 | u32 duration; |
@@ -306,6 +316,7 @@ enum ieee80211_sta_flags { | |||
306 | IEEE80211_STA_DISABLE_11N = BIT(4), | 316 | IEEE80211_STA_DISABLE_11N = BIT(4), |
307 | IEEE80211_STA_CSA_RECEIVED = BIT(5), | 317 | IEEE80211_STA_CSA_RECEIVED = BIT(5), |
308 | IEEE80211_STA_MFP_ENABLED = BIT(6), | 318 | IEEE80211_STA_MFP_ENABLED = BIT(6), |
319 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), | ||
309 | }; | 320 | }; |
310 | 321 | ||
311 | struct ieee80211_if_managed { | 322 | struct ieee80211_if_managed { |
@@ -494,8 +505,8 @@ struct ieee80211_sub_if_data { | |||
494 | */ | 505 | */ |
495 | struct ieee80211_if_ap *bss; | 506 | struct ieee80211_if_ap *bss; |
496 | 507 | ||
497 | int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ | 508 | /* bitmap of allowed (non-MCS) rate indexes for rate control */ |
498 | int max_ratectrl_rateidx; /* max TX rateidx for rate control */ | 509 | u32 rc_rateidx_mask[IEEE80211_NUM_BANDS]; |
499 | 510 | ||
500 | union { | 511 | union { |
501 | struct ieee80211_if_ap ap; | 512 | struct ieee80211_if_ap ap; |
@@ -797,6 +808,20 @@ struct ieee80211_local { | |||
797 | int wifi_wme_noack_test; | 808 | int wifi_wme_noack_test; |
798 | unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ | 809 | unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ |
799 | 810 | ||
811 | /* | ||
812 | * Bitmask of enabled u-apsd queues, | ||
813 | * IEEE80211_WMM_IE_STA_QOSINFO_AC_BE & co. Needs a new association | ||
814 | * to take effect. | ||
815 | */ | ||
816 | unsigned int uapsd_queues; | ||
817 | |||
818 | /* | ||
819 | * Maximum number of buffered frames AP can deliver during a | ||
820 | * service period, IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL or similar. | ||
821 | * Needs a new association to take effect. | ||
822 | */ | ||
823 | unsigned int uapsd_max_sp_len; | ||
824 | |||
800 | bool pspolling; | 825 | bool pspolling; |
801 | bool offchannel_ps_enabled; | 826 | bool offchannel_ps_enabled; |
802 | /* | 827 | /* |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 00a1f4ccdaf1..fe140bf033f9 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -15,12 +15,14 @@ | |||
15 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
16 | #include <linux/rtnetlink.h> | 16 | #include <linux/rtnetlink.h> |
17 | #include <net/mac80211.h> | 17 | #include <net/mac80211.h> |
18 | #include <net/ieee80211_radiotap.h> | ||
18 | #include "ieee80211_i.h" | 19 | #include "ieee80211_i.h" |
19 | #include "sta_info.h" | 20 | #include "sta_info.h" |
20 | #include "debugfs_netdev.h" | 21 | #include "debugfs_netdev.h" |
21 | #include "mesh.h" | 22 | #include "mesh.h" |
22 | #include "led.h" | 23 | #include "led.h" |
23 | #include "driver-ops.h" | 24 | #include "driver-ops.h" |
25 | #include "wme.h" | ||
24 | 26 | ||
25 | /** | 27 | /** |
26 | * DOC: Interface list locking | 28 | * DOC: Interface list locking |
@@ -63,15 +65,16 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | |||
63 | static int ieee80211_change_mac(struct net_device *dev, void *addr) | 65 | static int ieee80211_change_mac(struct net_device *dev, void *addr) |
64 | { | 66 | { |
65 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 67 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
68 | struct sockaddr *sa = addr; | ||
66 | int ret; | 69 | int ret; |
67 | 70 | ||
68 | if (ieee80211_sdata_running(sdata)) | 71 | if (ieee80211_sdata_running(sdata)) |
69 | return -EBUSY; | 72 | return -EBUSY; |
70 | 73 | ||
71 | ret = eth_mac_addr(dev, addr); | 74 | ret = eth_mac_addr(dev, sa); |
72 | 75 | ||
73 | if (ret == 0) | 76 | if (ret == 0) |
74 | memcpy(sdata->vif.addr, addr, ETH_ALEN); | 77 | memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN); |
75 | 78 | ||
76 | return ret; | 79 | return ret; |
77 | } | 80 | } |
@@ -326,7 +329,7 @@ static int ieee80211_open(struct net_device *dev) | |||
326 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 329 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
327 | ieee80211_queue_work(&local->hw, &sdata->u.mgd.work); | 330 | ieee80211_queue_work(&local->hw, &sdata->u.mgd.work); |
328 | 331 | ||
329 | netif_start_queue(dev); | 332 | netif_tx_start_all_queues(dev); |
330 | 333 | ||
331 | return 0; | 334 | return 0; |
332 | err_del_interface: | 335 | err_del_interface: |
@@ -354,7 +357,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
354 | /* | 357 | /* |
355 | * Stop TX on this interface first. | 358 | * Stop TX on this interface first. |
356 | */ | 359 | */ |
357 | netif_stop_queue(dev); | 360 | netif_tx_stop_all_queues(dev); |
358 | 361 | ||
359 | /* | 362 | /* |
360 | * Purge work for this interface. | 363 | * Purge work for this interface. |
@@ -657,6 +660,12 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
657 | WARN_ON(flushed); | 660 | WARN_ON(flushed); |
658 | } | 661 | } |
659 | 662 | ||
663 | static u16 ieee80211_netdev_select_queue(struct net_device *dev, | ||
664 | struct sk_buff *skb) | ||
665 | { | ||
666 | return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb); | ||
667 | } | ||
668 | |||
660 | static const struct net_device_ops ieee80211_dataif_ops = { | 669 | static const struct net_device_ops ieee80211_dataif_ops = { |
661 | .ndo_open = ieee80211_open, | 670 | .ndo_open = ieee80211_open, |
662 | .ndo_stop = ieee80211_stop, | 671 | .ndo_stop = ieee80211_stop, |
@@ -665,8 +674,34 @@ static const struct net_device_ops ieee80211_dataif_ops = { | |||
665 | .ndo_set_multicast_list = ieee80211_set_multicast_list, | 674 | .ndo_set_multicast_list = ieee80211_set_multicast_list, |
666 | .ndo_change_mtu = ieee80211_change_mtu, | 675 | .ndo_change_mtu = ieee80211_change_mtu, |
667 | .ndo_set_mac_address = ieee80211_change_mac, | 676 | .ndo_set_mac_address = ieee80211_change_mac, |
677 | .ndo_select_queue = ieee80211_netdev_select_queue, | ||
668 | }; | 678 | }; |
669 | 679 | ||
680 | static u16 ieee80211_monitor_select_queue(struct net_device *dev, | ||
681 | struct sk_buff *skb) | ||
682 | { | ||
683 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
684 | struct ieee80211_local *local = sdata->local; | ||
685 | struct ieee80211_hdr *hdr; | ||
686 | struct ieee80211_radiotap_header *rtap = (void *)skb->data; | ||
687 | |||
688 | if (local->hw.queues < 4) | ||
689 | return 0; | ||
690 | |||
691 | if (skb->len < 4 || | ||
692 | skb->len < rtap->it_len + 2 /* frame control */) | ||
693 | return 0; /* doesn't matter, frame will be dropped */ | ||
694 | |||
695 | hdr = (void *)((u8 *)skb->data + rtap->it_len); | ||
696 | |||
697 | if (!ieee80211_is_data(hdr->frame_control)) { | ||
698 | skb->priority = 7; | ||
699 | return ieee802_1d_to_ac[skb->priority]; | ||
700 | } | ||
701 | |||
702 | return ieee80211_downgrade_queue(local, skb); | ||
703 | } | ||
704 | |||
670 | static const struct net_device_ops ieee80211_monitorif_ops = { | 705 | static const struct net_device_ops ieee80211_monitorif_ops = { |
671 | .ndo_open = ieee80211_open, | 706 | .ndo_open = ieee80211_open, |
672 | .ndo_stop = ieee80211_stop, | 707 | .ndo_stop = ieee80211_stop, |
@@ -675,6 +710,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = { | |||
675 | .ndo_set_multicast_list = ieee80211_set_multicast_list, | 710 | .ndo_set_multicast_list = ieee80211_set_multicast_list, |
676 | .ndo_change_mtu = ieee80211_change_mtu, | 711 | .ndo_change_mtu = ieee80211_change_mtu, |
677 | .ndo_set_mac_address = eth_mac_addr, | 712 | .ndo_set_mac_address = eth_mac_addr, |
713 | .ndo_select_queue = ieee80211_monitor_select_queue, | ||
678 | }; | 714 | }; |
679 | 715 | ||
680 | static void ieee80211_if_setup(struct net_device *dev) | 716 | static void ieee80211_if_setup(struct net_device *dev) |
@@ -781,8 +817,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
781 | 817 | ||
782 | ASSERT_RTNL(); | 818 | ASSERT_RTNL(); |
783 | 819 | ||
784 | ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, | 820 | ndev = alloc_netdev_mq(sizeof(*sdata) + local->hw.vif_data_size, |
785 | name, ieee80211_if_setup); | 821 | name, ieee80211_if_setup, local->hw.queues); |
786 | if (!ndev) | 822 | if (!ndev) |
787 | return -ENOMEM; | 823 | return -ENOMEM; |
788 | dev_net_set(ndev, wiphy_net(local->hw.wiphy)); | 824 | dev_net_set(ndev, wiphy_net(local->hw.wiphy)); |
@@ -820,8 +856,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
820 | 856 | ||
821 | INIT_LIST_HEAD(&sdata->key_list); | 857 | INIT_LIST_HEAD(&sdata->key_list); |
822 | 858 | ||
823 | sdata->force_unicast_rateidx = -1; | 859 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
824 | sdata->max_ratectrl_rateidx = -1; | 860 | struct ieee80211_supported_band *sband; |
861 | sband = local->hw.wiphy->bands[i]; | ||
862 | sdata->rc_rateidx_mask[i] = | ||
863 | sband ? (1 << sband->n_bitrates) - 1 : 0; | ||
864 | } | ||
825 | 865 | ||
826 | /* setup type-dependent data */ | 866 | /* setup type-dependent data */ |
827 | ieee80211_setup_sdata(sdata, type); | 867 | ieee80211_setup_sdata(sdata, type); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d0a14d953f08..ec8f767ba95b 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <linux/skbuff.h> | 17 | #include <linux/skbuff.h> |
18 | #include <linux/etherdevice.h> | 18 | #include <linux/etherdevice.h> |
19 | #include <linux/if_arp.h> | 19 | #include <linux/if_arp.h> |
20 | #include <linux/wireless.h> | ||
21 | #include <linux/rtnetlink.h> | 20 | #include <linux/rtnetlink.h> |
22 | #include <linux/bitmap.h> | 21 | #include <linux/bitmap.h> |
23 | #include <linux/pm_qos_params.h> | 22 | #include <linux/pm_qos_params.h> |
@@ -385,6 +384,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
385 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; | 384 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; |
386 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; | 385 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; |
387 | local->user_power_level = -1; | 386 | local->user_power_level = -1; |
387 | local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; | ||
388 | local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; | ||
388 | 389 | ||
389 | INIT_LIST_HEAD(&local->interfaces); | 390 | INIT_LIST_HEAD(&local->interfaces); |
390 | mutex_init(&local->iflist_mtx); | 391 | mutex_init(&local->iflist_mtx); |
@@ -492,6 +493,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
492 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | 493 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) |
493 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; | 494 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; |
494 | 495 | ||
496 | WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) | ||
497 | && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK), | ||
498 | "U-APSD not supported with HW_PS_NULLFUNC_STACK\n"); | ||
499 | |||
495 | /* | 500 | /* |
496 | * Calculate scan IE length -- we need this to alloc | 501 | * Calculate scan IE length -- we need this to alloc |
497 | * memory and to subtract from the driver limit. It | 502 | * memory and to subtract from the driver limit. It |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 72920ee07885..a82564e73d91 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -249,30 +249,15 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
249 | void ieee80211_send_pspoll(struct ieee80211_local *local, | 249 | void ieee80211_send_pspoll(struct ieee80211_local *local, |
250 | struct ieee80211_sub_if_data *sdata) | 250 | struct ieee80211_sub_if_data *sdata) |
251 | { | 251 | { |
252 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
253 | struct ieee80211_pspoll *pspoll; | 252 | struct ieee80211_pspoll *pspoll; |
254 | struct sk_buff *skb; | 253 | struct sk_buff *skb; |
255 | u16 fc; | ||
256 | 254 | ||
257 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll)); | 255 | skb = ieee80211_pspoll_get(&local->hw, &sdata->vif); |
258 | if (!skb) { | 256 | if (!skb) |
259 | printk(KERN_DEBUG "%s: failed to allocate buffer for " | ||
260 | "pspoll frame\n", sdata->name); | ||
261 | return; | 257 | return; |
262 | } | ||
263 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
264 | |||
265 | pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll)); | ||
266 | memset(pspoll, 0, sizeof(*pspoll)); | ||
267 | fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM; | ||
268 | pspoll->frame_control = cpu_to_le16(fc); | ||
269 | pspoll->aid = cpu_to_le16(ifmgd->aid); | ||
270 | |||
271 | /* aid in PS-Poll has its two MSBs each set to 1 */ | ||
272 | pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); | ||
273 | 258 | ||
274 | memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN); | 259 | pspoll = (struct ieee80211_pspoll *) skb->data; |
275 | memcpy(pspoll->ta, sdata->vif.addr, ETH_ALEN); | 260 | pspoll->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); |
276 | 261 | ||
277 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 262 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
278 | ieee80211_tx_skb(sdata, skb); | 263 | ieee80211_tx_skb(sdata, skb); |
@@ -283,30 +268,47 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
283 | int powersave) | 268 | int powersave) |
284 | { | 269 | { |
285 | struct sk_buff *skb; | 270 | struct sk_buff *skb; |
271 | struct ieee80211_hdr_3addr *nullfunc; | ||
272 | |||
273 | skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif); | ||
274 | if (!skb) | ||
275 | return; | ||
276 | |||
277 | nullfunc = (struct ieee80211_hdr_3addr *) skb->data; | ||
278 | if (powersave) | ||
279 | nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
280 | |||
281 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
282 | ieee80211_tx_skb(sdata, skb); | ||
283 | } | ||
284 | |||
285 | static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, | ||
286 | struct ieee80211_sub_if_data *sdata) | ||
287 | { | ||
288 | struct sk_buff *skb; | ||
286 | struct ieee80211_hdr *nullfunc; | 289 | struct ieee80211_hdr *nullfunc; |
287 | __le16 fc; | 290 | __le16 fc; |
288 | 291 | ||
289 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | 292 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) |
290 | return; | 293 | return; |
291 | 294 | ||
292 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); | 295 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30); |
293 | if (!skb) { | 296 | if (!skb) { |
294 | printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " | 297 | printk(KERN_DEBUG "%s: failed to allocate buffer for 4addr " |
295 | "frame\n", sdata->name); | 298 | "nullfunc frame\n", sdata->name); |
296 | return; | 299 | return; |
297 | } | 300 | } |
298 | skb_reserve(skb, local->hw.extra_tx_headroom); | 301 | skb_reserve(skb, local->hw.extra_tx_headroom); |
299 | 302 | ||
300 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); | 303 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 30); |
301 | memset(nullfunc, 0, 24); | 304 | memset(nullfunc, 0, 30); |
302 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | | 305 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | |
303 | IEEE80211_FCTL_TODS); | 306 | IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
304 | if (powersave) | ||
305 | fc |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
306 | nullfunc->frame_control = fc; | 307 | nullfunc->frame_control = fc; |
307 | memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); | 308 | memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); |
308 | memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); | 309 | memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); |
309 | memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); | 310 | memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); |
311 | memcpy(nullfunc->addr4, sdata->vif.addr, ETH_ALEN); | ||
310 | 312 | ||
311 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 313 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
312 | ieee80211_tx_skb(sdata, skb); | 314 | ieee80211_tx_skb(sdata, skb); |
@@ -567,7 +569,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
567 | struct ieee80211_tx_queue_params params; | 569 | struct ieee80211_tx_queue_params params; |
568 | size_t left; | 570 | size_t left; |
569 | int count; | 571 | int count; |
570 | u8 *pos; | 572 | u8 *pos, uapsd_queues = 0; |
571 | 573 | ||
572 | if (local->hw.queues < 4) | 574 | if (local->hw.queues < 4) |
573 | return; | 575 | return; |
@@ -577,6 +579,10 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
577 | 579 | ||
578 | if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) | 580 | if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) |
579 | return; | 581 | return; |
582 | |||
583 | if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) | ||
584 | uapsd_queues = local->uapsd_queues; | ||
585 | |||
580 | count = wmm_param[6] & 0x0f; | 586 | count = wmm_param[6] & 0x0f; |
581 | if (count == ifmgd->wmm_last_param_set) | 587 | if (count == ifmgd->wmm_last_param_set) |
582 | return; | 588 | return; |
@@ -591,6 +597,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
591 | for (; left >= 4; left -= 4, pos += 4) { | 597 | for (; left >= 4; left -= 4, pos += 4) { |
592 | int aci = (pos[0] >> 5) & 0x03; | 598 | int aci = (pos[0] >> 5) & 0x03; |
593 | int acm = (pos[0] >> 4) & 0x01; | 599 | int acm = (pos[0] >> 4) & 0x01; |
600 | bool uapsd = false; | ||
594 | int queue; | 601 | int queue; |
595 | 602 | ||
596 | switch (aci) { | 603 | switch (aci) { |
@@ -598,22 +605,30 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
598 | queue = 3; | 605 | queue = 3; |
599 | if (acm) | 606 | if (acm) |
600 | local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ | 607 | local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ |
608 | if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) | ||
609 | uapsd = true; | ||
601 | break; | 610 | break; |
602 | case 2: /* AC_VI */ | 611 | case 2: /* AC_VI */ |
603 | queue = 1; | 612 | queue = 1; |
604 | if (acm) | 613 | if (acm) |
605 | local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ | 614 | local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ |
615 | if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) | ||
616 | uapsd = true; | ||
606 | break; | 617 | break; |
607 | case 3: /* AC_VO */ | 618 | case 3: /* AC_VO */ |
608 | queue = 0; | 619 | queue = 0; |
609 | if (acm) | 620 | if (acm) |
610 | local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ | 621 | local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ |
622 | if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) | ||
623 | uapsd = true; | ||
611 | break; | 624 | break; |
612 | case 0: /* AC_BE */ | 625 | case 0: /* AC_BE */ |
613 | default: | 626 | default: |
614 | queue = 2; | 627 | queue = 2; |
615 | if (acm) | 628 | if (acm) |
616 | local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ | 629 | local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ |
630 | if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) | ||
631 | uapsd = true; | ||
617 | break; | 632 | break; |
618 | } | 633 | } |
619 | 634 | ||
@@ -621,11 +636,14 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
621 | params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); | 636 | params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); |
622 | params.cw_min = ecw2cw(pos[1] & 0x0f); | 637 | params.cw_min = ecw2cw(pos[1] & 0x0f); |
623 | params.txop = get_unaligned_le16(pos + 2); | 638 | params.txop = get_unaligned_le16(pos + 2); |
639 | params.uapsd = uapsd; | ||
640 | |||
624 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 641 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
625 | printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " | 642 | printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " |
626 | "cWmin=%d cWmax=%d txop=%d\n", | 643 | "cWmin=%d cWmax=%d txop=%d uapsd=%d\n", |
627 | wiphy_name(local->hw.wiphy), queue, aci, acm, | 644 | wiphy_name(local->hw.wiphy), queue, aci, acm, |
628 | params.aifs, params.cw_min, params.cw_max, params.txop); | 645 | params.aifs, params.cw_min, params.cw_max, params.txop, |
646 | params.uapsd); | ||
629 | #endif | 647 | #endif |
630 | if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx) | 648 | if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx) |
631 | printk(KERN_DEBUG "%s: failed to set TX queue " | 649 | printk(KERN_DEBUG "%s: failed to set TX queue " |
@@ -652,6 +670,8 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
652 | } | 670 | } |
653 | 671 | ||
654 | use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); | 672 | use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); |
673 | if (sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) | ||
674 | use_short_slot = true; | ||
655 | 675 | ||
656 | if (use_protection != bss_conf->use_cts_prot) { | 676 | if (use_protection != bss_conf->use_cts_prot) { |
657 | bss_conf->use_cts_prot = use_protection; | 677 | bss_conf->use_cts_prot = use_protection; |
@@ -723,7 +743,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
723 | ieee80211_recalc_smps(local, sdata); | 743 | ieee80211_recalc_smps(local, sdata); |
724 | mutex_unlock(&local->iflist_mtx); | 744 | mutex_unlock(&local->iflist_mtx); |
725 | 745 | ||
726 | netif_start_queue(sdata->dev); | 746 | netif_tx_start_all_queues(sdata->dev); |
727 | netif_carrier_on(sdata->dev); | 747 | netif_carrier_on(sdata->dev); |
728 | } | 748 | } |
729 | 749 | ||
@@ -759,7 +779,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) | |||
759 | * time -- we don't want the scan code to enable queues. | 779 | * time -- we don't want the scan code to enable queues. |
760 | */ | 780 | */ |
761 | 781 | ||
762 | netif_stop_queue(sdata->dev); | 782 | netif_tx_stop_all_queues(sdata->dev); |
763 | netif_carrier_off(sdata->dev); | 783 | netif_carrier_off(sdata->dev); |
764 | 784 | ||
765 | rcu_read_lock(); | 785 | rcu_read_lock(); |
@@ -1096,7 +1116,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1096 | if (err) { | 1116 | if (err) { |
1097 | printk(KERN_DEBUG "%s: failed to insert STA entry for" | 1117 | printk(KERN_DEBUG "%s: failed to insert STA entry for" |
1098 | " the AP (error %d)\n", sdata->name, err); | 1118 | " the AP (error %d)\n", sdata->name, err); |
1099 | return RX_MGMT_CFG80211_ASSOC_ERROR; | 1119 | return false; |
1100 | } | 1120 | } |
1101 | 1121 | ||
1102 | if (elems.wmm_param) | 1122 | if (elems.wmm_param) |
@@ -1120,6 +1140,13 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1120 | ieee80211_set_associated(sdata, cbss, changed); | 1140 | ieee80211_set_associated(sdata, cbss, changed); |
1121 | 1141 | ||
1122 | /* | 1142 | /* |
1143 | * If we're using 4-addr mode, let the AP know that we're | ||
1144 | * doing so, so that it can create the STA VLAN on its side | ||
1145 | */ | ||
1146 | if (ifmgd->use_4addr) | ||
1147 | ieee80211_send_4addr_nullfunc(local, sdata); | ||
1148 | |||
1149 | /* | ||
1123 | * Start timer to probe the connection to the AP now. | 1150 | * Start timer to probe the connection to the AP now. |
1124 | * Also start the timer that will detect beacon loss. | 1151 | * Also start the timer that will detect beacon loss. |
1125 | */ | 1152 | */ |
@@ -1774,7 +1801,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
1774 | if (!wk) | 1801 | if (!wk) |
1775 | return -ENOMEM; | 1802 | return -ENOMEM; |
1776 | 1803 | ||
1777 | memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN);; | 1804 | memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); |
1778 | 1805 | ||
1779 | if (req->ie && req->ie_len) { | 1806 | if (req->ie && req->ie_len) { |
1780 | memcpy(wk->ie, req->ie, req->ie_len); | 1807 | memcpy(wk->ie, req->ie, req->ie_len); |
@@ -1897,6 +1924,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
1897 | wk->assoc.ht_information_ie = | 1924 | wk->assoc.ht_information_ie = |
1898 | ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); | 1925 | ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); |
1899 | 1926 | ||
1927 | if (bss->wmm_used && bss->uapsd_supported && | ||
1928 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { | ||
1929 | wk->assoc.uapsd_used = true; | ||
1930 | ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; | ||
1931 | } else { | ||
1932 | wk->assoc.uapsd_used = false; | ||
1933 | ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED; | ||
1934 | } | ||
1935 | |||
1900 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | 1936 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); |
1901 | memcpy(wk->assoc.ssid, ssid + 2, ssid[1]); | 1937 | memcpy(wk->assoc.ssid, ssid + 2, ssid[1]); |
1902 | wk->assoc.ssid_len = ssid[1]; | 1938 | wk->assoc.ssid_len = ssid[1]; |
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index a7bbfc40a648..c36b1911987a 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -113,7 +113,7 @@ void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local) | |||
113 | */ | 113 | */ |
114 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 114 | if (sdata->vif.type != NL80211_IFTYPE_STATION && |
115 | sdata->vif.type != NL80211_IFTYPE_MONITOR) | 115 | sdata->vif.type != NL80211_IFTYPE_MONITOR) |
116 | netif_stop_queue(sdata->dev); | 116 | netif_tx_stop_all_queues(sdata->dev); |
117 | } | 117 | } |
118 | mutex_unlock(&local->iflist_mtx); | 118 | mutex_unlock(&local->iflist_mtx); |
119 | } | 119 | } |
@@ -131,7 +131,7 @@ void ieee80211_offchannel_stop_station(struct ieee80211_local *local) | |||
131 | continue; | 131 | continue; |
132 | 132 | ||
133 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 133 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
134 | netif_stop_queue(sdata->dev); | 134 | netif_tx_stop_all_queues(sdata->dev); |
135 | if (sdata->u.mgd.associated) | 135 | if (sdata->u.mgd.associated) |
136 | ieee80211_offchannel_ps_enable(sdata); | 136 | ieee80211_offchannel_ps_enable(sdata); |
137 | } | 137 | } |
@@ -153,9 +153,11 @@ void ieee80211_offchannel_return(struct ieee80211_local *local, | |||
153 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 153 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
154 | if (sdata->u.mgd.associated) | 154 | if (sdata->u.mgd.associated) |
155 | ieee80211_offchannel_ps_disable(sdata); | 155 | ieee80211_offchannel_ps_disable(sdata); |
156 | netif_wake_queue(sdata->dev); | ||
157 | } | 156 | } |
158 | 157 | ||
158 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | ||
159 | netif_tx_wake_all_queues(sdata->dev); | ||
160 | |||
159 | /* re-enable beaconing */ | 161 | /* re-enable beaconing */ |
160 | if (enable_beaconing && | 162 | if (enable_beaconing && |
161 | (sdata->vif.type == NL80211_IFTYPE_AP || | 163 | (sdata->vif.type == NL80211_IFTYPE_AP || |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index b9007f80cb92..c74b7c85403c 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -207,6 +207,27 @@ static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc) | |||
207 | return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc)); | 207 | return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc)); |
208 | } | 208 | } |
209 | 209 | ||
210 | static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u8 max_rate_idx) | ||
211 | { | ||
212 | u8 i; | ||
213 | |||
214 | if (basic_rates == 0) | ||
215 | return; /* assume basic rates unknown and accept rate */ | ||
216 | if (*idx < 0) | ||
217 | return; | ||
218 | if (basic_rates & (1 << *idx)) | ||
219 | return; /* selected rate is a basic rate */ | ||
220 | |||
221 | for (i = *idx + 1; i <= max_rate_idx; i++) { | ||
222 | if (basic_rates & (1 << i)) { | ||
223 | *idx = i; | ||
224 | return; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | /* could not find a basic rate; use original selection */ | ||
229 | } | ||
230 | |||
210 | bool rate_control_send_low(struct ieee80211_sta *sta, | 231 | bool rate_control_send_low(struct ieee80211_sta *sta, |
211 | void *priv_sta, | 232 | void *priv_sta, |
212 | struct ieee80211_tx_rate_control *txrc) | 233 | struct ieee80211_tx_rate_control *txrc) |
@@ -218,12 +239,48 @@ bool rate_control_send_low(struct ieee80211_sta *sta, | |||
218 | info->control.rates[0].count = | 239 | info->control.rates[0].count = |
219 | (info->flags & IEEE80211_TX_CTL_NO_ACK) ? | 240 | (info->flags & IEEE80211_TX_CTL_NO_ACK) ? |
220 | 1 : txrc->hw->max_rate_tries; | 241 | 1 : txrc->hw->max_rate_tries; |
242 | if (!sta && txrc->ap) | ||
243 | rc_send_low_broadcast(&info->control.rates[0].idx, | ||
244 | txrc->bss_conf->basic_rates, | ||
245 | txrc->sband->n_bitrates); | ||
221 | return true; | 246 | return true; |
222 | } | 247 | } |
223 | return false; | 248 | return false; |
224 | } | 249 | } |
225 | EXPORT_SYMBOL(rate_control_send_low); | 250 | EXPORT_SYMBOL(rate_control_send_low); |
226 | 251 | ||
252 | static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, | ||
253 | int n_bitrates, u32 mask) | ||
254 | { | ||
255 | int j; | ||
256 | |||
257 | /* See whether the selected rate or anything below it is allowed. */ | ||
258 | for (j = rate->idx; j >= 0; j--) { | ||
259 | if (mask & (1 << j)) { | ||
260 | /* Okay, found a suitable rate. Use it. */ | ||
261 | rate->idx = j; | ||
262 | return; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | /* Try to find a higher rate that would be allowed */ | ||
267 | for (j = rate->idx + 1; j < n_bitrates; j++) { | ||
268 | if (mask & (1 << j)) { | ||
269 | /* Okay, found a suitable rate. Use it. */ | ||
270 | rate->idx = j; | ||
271 | return; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | /* | ||
276 | * Uh.. No suitable rate exists. This should not really happen with | ||
277 | * sane TX rate mask configurations. However, should someone manage to | ||
278 | * configure supported rates and TX rate mask in incompatible way, | ||
279 | * allow the frame to be transmitted with whatever the rate control | ||
280 | * selected. | ||
281 | */ | ||
282 | } | ||
283 | |||
227 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | 284 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, |
228 | struct sta_info *sta, | 285 | struct sta_info *sta, |
229 | struct ieee80211_tx_rate_control *txrc) | 286 | struct ieee80211_tx_rate_control *txrc) |
@@ -233,6 +290,7 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | |||
233 | struct ieee80211_sta *ista = NULL; | 290 | struct ieee80211_sta *ista = NULL; |
234 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); | 291 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); |
235 | int i; | 292 | int i; |
293 | u32 mask; | ||
236 | 294 | ||
237 | if (sta) { | 295 | if (sta) { |
238 | ista = &sta->sta; | 296 | ista = &sta->sta; |
@@ -245,23 +303,31 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | |||
245 | info->control.rates[i].count = 1; | 303 | info->control.rates[i].count = 1; |
246 | } | 304 | } |
247 | 305 | ||
248 | if (sta && sdata->force_unicast_rateidx > -1) { | 306 | ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); |
249 | info->control.rates[0].idx = sdata->force_unicast_rateidx; | ||
250 | } else { | ||
251 | ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); | ||
252 | info->flags |= IEEE80211_TX_INTFL_RCALGO; | ||
253 | } | ||
254 | 307 | ||
255 | /* | 308 | /* |
256 | * try to enforce the maximum rate the user wanted | 309 | * Try to enforce the rateidx mask the user wanted. skip this if the |
310 | * default mask (allow all rates) is used to save some processing for | ||
311 | * the common case. | ||
257 | */ | 312 | */ |
258 | if (sdata->max_ratectrl_rateidx > -1) | 313 | mask = sdata->rc_rateidx_mask[info->band]; |
314 | if (mask != (1 << txrc->sband->n_bitrates) - 1) { | ||
315 | if (sta) { | ||
316 | /* Filter out rates that the STA does not support */ | ||
317 | mask &= sta->sta.supp_rates[info->band]; | ||
318 | } | ||
319 | /* | ||
320 | * Make sure the rate index selected for each TX rate is | ||
321 | * included in the configured mask and change the rate indexes | ||
322 | * if needed. | ||
323 | */ | ||
259 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 324 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
325 | /* Rate masking supports only legacy rates for now */ | ||
260 | if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) | 326 | if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) |
261 | continue; | 327 | continue; |
262 | info->control.rates[i].idx = | 328 | rate_idx_match_mask(&info->control.rates[i], |
263 | min_t(s8, info->control.rates[i].idx, | 329 | txrc->sband->n_bitrates, mask); |
264 | sdata->max_ratectrl_rateidx); | 330 | } |
265 | } | 331 | } |
266 | 332 | ||
267 | BUG_ON(info->control.rates[0].idx < 0); | 333 | BUG_ON(info->control.rates[0].idx < 0); |
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index cb9bd1f65e27..669dddd40521 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -44,10 +44,7 @@ static inline void rate_control_tx_status(struct ieee80211_local *local, | |||
44 | struct rate_control_ref *ref = local->rate_ctrl; | 44 | struct rate_control_ref *ref = local->rate_ctrl; |
45 | struct ieee80211_sta *ista = &sta->sta; | 45 | struct ieee80211_sta *ista = &sta->sta; |
46 | void *priv_sta = sta->rate_ctrl_priv; | 46 | void *priv_sta = sta->rate_ctrl_priv; |
47 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 47 | ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); |
48 | |||
49 | if (likely(info->flags & IEEE80211_TX_INTFL_RCALGO)) | ||
50 | ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); | ||
51 | } | 48 | } |
52 | 49 | ||
53 | 50 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index bfcf09eb64b4..efa6d3689c5e 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1111,6 +1111,18 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1111 | if (ieee80211_is_nullfunc(hdr->frame_control) || | 1111 | if (ieee80211_is_nullfunc(hdr->frame_control) || |
1112 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | 1112 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { |
1113 | I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); | 1113 | I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); |
1114 | |||
1115 | /* | ||
1116 | * If we receive a 4-addr nullfunc frame from a STA | ||
1117 | * that was not moved to a 4-addr STA vlan yet, drop | ||
1118 | * the frame to the monitor interface, to make sure | ||
1119 | * that hostapd sees it | ||
1120 | */ | ||
1121 | if (ieee80211_has_a4(hdr->frame_control) && | ||
1122 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || | ||
1123 | (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && | ||
1124 | !rx->sdata->u.vlan.sta))) | ||
1125 | return RX_DROP_MONITOR; | ||
1114 | /* | 1126 | /* |
1115 | * Update counter and free packet here to avoid | 1127 | * Update counter and free packet here to avoid |
1116 | * counting this as a dropped packed. | 1128 | * counting this as a dropped packed. |
@@ -1665,7 +1677,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1665 | memset(info, 0, sizeof(*info)); | 1677 | memset(info, 0, sizeof(*info)); |
1666 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 1678 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
1667 | info->control.vif = &rx->sdata->vif; | 1679 | info->control.vif = &rx->sdata->vif; |
1668 | ieee80211_select_queue(local, fwd_skb); | 1680 | skb_set_queue_mapping(skb, |
1681 | ieee80211_select_queue(rx->sdata, fwd_skb)); | ||
1682 | ieee80211_set_qos_hdr(local, skb); | ||
1669 | if (is_multicast_ether_addr(fwd_hdr->addr1)) | 1683 | if (is_multicast_ether_addr(fwd_hdr->addr1)) |
1670 | IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, | 1684 | IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, |
1671 | fwded_mcast); | 1685 | fwded_mcast); |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 365f40975511..9afe2f9885dc 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -12,7 +12,6 @@ | |||
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/wireless.h> | ||
16 | #include <linux/if_arp.h> | 15 | #include <linux/if_arp.h> |
17 | #include <linux/rtnetlink.h> | 16 | #include <linux/rtnetlink.h> |
18 | #include <net/mac80211.h> | 17 | #include <net/mac80211.h> |
@@ -55,6 +54,23 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local, | |||
55 | cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv)); | 54 | cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv)); |
56 | } | 55 | } |
57 | 56 | ||
57 | static bool is_uapsd_supported(struct ieee802_11_elems *elems) | ||
58 | { | ||
59 | u8 qos_info; | ||
60 | |||
61 | if (elems->wmm_info && elems->wmm_info_len == 7 | ||
62 | && elems->wmm_info[5] == 1) | ||
63 | qos_info = elems->wmm_info[6]; | ||
64 | else if (elems->wmm_param && elems->wmm_param_len == 24 | ||
65 | && elems->wmm_param[5] == 1) | ||
66 | qos_info = elems->wmm_param[6]; | ||
67 | else | ||
68 | /* no valid wmm information or parameter element found */ | ||
69 | return false; | ||
70 | |||
71 | return qos_info & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD; | ||
72 | } | ||
73 | |||
58 | struct ieee80211_bss * | 74 | struct ieee80211_bss * |
59 | ieee80211_bss_info_update(struct ieee80211_local *local, | 75 | ieee80211_bss_info_update(struct ieee80211_local *local, |
60 | struct ieee80211_rx_status *rx_status, | 76 | struct ieee80211_rx_status *rx_status, |
@@ -118,6 +134,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
118 | } | 134 | } |
119 | 135 | ||
120 | bss->wmm_used = elems->wmm_param || elems->wmm_info; | 136 | bss->wmm_used = elems->wmm_param || elems->wmm_info; |
137 | bss->uapsd_supported = is_uapsd_supported(elems); | ||
121 | 138 | ||
122 | if (!beacon) | 139 | if (!beacon) |
123 | bss->last_probe_resp = jiffies; | 140 | bss->last_probe_resp = jiffies; |
@@ -285,6 +302,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
285 | ieee80211_mlme_notify_scan_completed(local); | 302 | ieee80211_mlme_notify_scan_completed(local); |
286 | ieee80211_ibss_notify_scan_completed(local); | 303 | ieee80211_ibss_notify_scan_completed(local); |
287 | ieee80211_mesh_notify_scan_completed(local); | 304 | ieee80211_mesh_notify_scan_completed(local); |
305 | ieee80211_queue_work(&local->hw, &local->work_work); | ||
288 | } | 306 | } |
289 | EXPORT_SYMBOL(ieee80211_scan_completed); | 307 | EXPORT_SYMBOL(ieee80211_scan_completed); |
290 | 308 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 47da552ce8a6..f735826f055c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -119,6 +119,27 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, | |||
119 | return sta; | 119 | return sta; |
120 | } | 120 | } |
121 | 121 | ||
122 | /* | ||
123 | * Get sta info either from the specified interface | ||
124 | * or from one of its vlans | ||
125 | */ | ||
126 | struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, | ||
127 | const u8 *addr) | ||
128 | { | ||
129 | struct ieee80211_local *local = sdata->local; | ||
130 | struct sta_info *sta; | ||
131 | |||
132 | sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]); | ||
133 | while (sta) { | ||
134 | if ((sta->sdata == sdata || | ||
135 | sta->sdata->bss == sdata->bss) && | ||
136 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | ||
137 | break; | ||
138 | sta = rcu_dereference(sta->hnext); | ||
139 | } | ||
140 | return sta; | ||
141 | } | ||
142 | |||
122 | struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, | 143 | struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, |
123 | int idx) | 144 | int idx) |
124 | { | 145 | { |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index c8208236e896..6f79bba5706e 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -408,6 +408,9 @@ static inline u32 get_sta_flags(struct sta_info *sta) | |||
408 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, | 408 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, |
409 | const u8 *addr); | 409 | const u8 *addr); |
410 | 410 | ||
411 | struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, | ||
412 | const u8 *addr); | ||
413 | |||
411 | static inline | 414 | static inline |
412 | void for_each_sta_info_type_check(struct ieee80211_local *local, | 415 | void for_each_sta_info_type_check(struct ieee80211_local *local, |
413 | const u8 *addr, | 416 | const u8 *addr, |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7bba49d2b6ca..daf81048c1f7 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -180,6 +180,71 @@ static int inline is_ieee80211_device(struct ieee80211_local *local, | |||
180 | } | 180 | } |
181 | 181 | ||
182 | /* tx handlers */ | 182 | /* tx handlers */ |
183 | static ieee80211_tx_result debug_noinline | ||
184 | ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) | ||
185 | { | ||
186 | struct ieee80211_local *local = tx->local; | ||
187 | struct ieee80211_if_managed *ifmgd; | ||
188 | |||
189 | /* driver doesn't support power save */ | ||
190 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) | ||
191 | return TX_CONTINUE; | ||
192 | |||
193 | /* hardware does dynamic power save */ | ||
194 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | ||
195 | return TX_CONTINUE; | ||
196 | |||
197 | /* dynamic power save disabled */ | ||
198 | if (local->hw.conf.dynamic_ps_timeout <= 0) | ||
199 | return TX_CONTINUE; | ||
200 | |||
201 | /* we are scanning, don't enable power save */ | ||
202 | if (local->scanning) | ||
203 | return TX_CONTINUE; | ||
204 | |||
205 | if (!local->ps_sdata) | ||
206 | return TX_CONTINUE; | ||
207 | |||
208 | /* No point if we're going to suspend */ | ||
209 | if (local->quiescing) | ||
210 | return TX_CONTINUE; | ||
211 | |||
212 | /* dynamic ps is supported only in managed mode */ | ||
213 | if (tx->sdata->vif.type != NL80211_IFTYPE_STATION) | ||
214 | return TX_CONTINUE; | ||
215 | |||
216 | ifmgd = &tx->sdata->u.mgd; | ||
217 | |||
218 | /* | ||
219 | * Don't wakeup from power save if u-apsd is enabled, voip ac has | ||
220 | * u-apsd enabled and the frame is in voip class. This effectively | ||
221 | * means that even if all access categories have u-apsd enabled, in | ||
222 | * practise u-apsd is only used with the voip ac. This is a | ||
223 | * workaround for the case when received voip class packets do not | ||
224 | * have correct qos tag for some reason, due the network or the | ||
225 | * peer application. | ||
226 | * | ||
227 | * Note: local->uapsd_queues access is racy here. If the value is | ||
228 | * changed via debugfs, user needs to reassociate manually to have | ||
229 | * everything in sync. | ||
230 | */ | ||
231 | if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) | ||
232 | && (local->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) | ||
233 | && skb_get_queue_mapping(tx->skb) == 0) | ||
234 | return TX_CONTINUE; | ||
235 | |||
236 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
237 | ieee80211_stop_queues_by_reason(&local->hw, | ||
238 | IEEE80211_QUEUE_STOP_REASON_PS); | ||
239 | ieee80211_queue_work(&local->hw, | ||
240 | &local->dynamic_ps_disable_work); | ||
241 | } | ||
242 | |||
243 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
244 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | ||
245 | |||
246 | return TX_CONTINUE; | ||
247 | } | ||
183 | 248 | ||
184 | static ieee80211_tx_result debug_noinline | 249 | static ieee80211_tx_result debug_noinline |
185 | ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) | 250 | ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) |
@@ -519,7 +584,12 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
519 | txrc.bss_conf = &tx->sdata->vif.bss_conf; | 584 | txrc.bss_conf = &tx->sdata->vif.bss_conf; |
520 | txrc.skb = tx->skb; | 585 | txrc.skb = tx->skb; |
521 | txrc.reported_rate.idx = -1; | 586 | txrc.reported_rate.idx = -1; |
522 | txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx; | 587 | txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[tx->channel->band]; |
588 | if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1) | ||
589 | txrc.max_rate_idx = -1; | ||
590 | else | ||
591 | txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | ||
592 | txrc.ap = tx->sdata->vif.type == NL80211_IFTYPE_AP; | ||
523 | 593 | ||
524 | /* set up RTS protection if desired */ | 594 | /* set up RTS protection if desired */ |
525 | if (len > tx->local->hw.wiphy->rts_threshold) { | 595 | if (len > tx->local->hw.wiphy->rts_threshold) { |
@@ -1051,8 +1121,11 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1051 | 1121 | ||
1052 | hdr = (struct ieee80211_hdr *) skb->data; | 1122 | hdr = (struct ieee80211_hdr *) skb->data; |
1053 | 1123 | ||
1054 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 1124 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { |
1055 | tx->sta = rcu_dereference(sdata->u.vlan.sta); | 1125 | tx->sta = rcu_dereference(sdata->u.vlan.sta); |
1126 | if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr) | ||
1127 | return TX_DROP; | ||
1128 | } | ||
1056 | if (!tx->sta) | 1129 | if (!tx->sta) |
1057 | tx->sta = sta_info_get(sdata, hdr->addr1); | 1130 | tx->sta = sta_info_get(sdata, hdr->addr1); |
1058 | 1131 | ||
@@ -1215,6 +1288,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1215 | goto txh_done; \ | 1288 | goto txh_done; \ |
1216 | } while (0) | 1289 | } while (0) |
1217 | 1290 | ||
1291 | CALL_TXH(ieee80211_tx_h_dynamic_ps); | ||
1218 | CALL_TXH(ieee80211_tx_h_check_assoc); | 1292 | CALL_TXH(ieee80211_tx_h_check_assoc); |
1219 | CALL_TXH(ieee80211_tx_h_ps_buf); | 1293 | CALL_TXH(ieee80211_tx_h_ps_buf); |
1220 | CALL_TXH(ieee80211_tx_h_select_key); | 1294 | CALL_TXH(ieee80211_tx_h_select_key); |
@@ -1397,34 +1471,6 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, | |||
1397 | return 0; | 1471 | return 0; |
1398 | } | 1472 | } |
1399 | 1473 | ||
1400 | static bool need_dynamic_ps(struct ieee80211_local *local) | ||
1401 | { | ||
1402 | /* driver doesn't support power save */ | ||
1403 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) | ||
1404 | return false; | ||
1405 | |||
1406 | /* hardware does dynamic power save */ | ||
1407 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | ||
1408 | return false; | ||
1409 | |||
1410 | /* dynamic power save disabled */ | ||
1411 | if (local->hw.conf.dynamic_ps_timeout <= 0) | ||
1412 | return false; | ||
1413 | |||
1414 | /* we are scanning, don't enable power save */ | ||
1415 | if (local->scanning) | ||
1416 | return false; | ||
1417 | |||
1418 | if (!local->ps_sdata) | ||
1419 | return false; | ||
1420 | |||
1421 | /* No point if we're going to suspend */ | ||
1422 | if (local->quiescing) | ||
1423 | return false; | ||
1424 | |||
1425 | return true; | ||
1426 | } | ||
1427 | |||
1428 | static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | 1474 | static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, |
1429 | struct sk_buff *skb) | 1475 | struct sk_buff *skb) |
1430 | { | 1476 | { |
@@ -1435,18 +1481,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
1435 | int headroom; | 1481 | int headroom; |
1436 | bool may_encrypt; | 1482 | bool may_encrypt; |
1437 | 1483 | ||
1438 | if (need_dynamic_ps(local)) { | ||
1439 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
1440 | ieee80211_stop_queues_by_reason(&local->hw, | ||
1441 | IEEE80211_QUEUE_STOP_REASON_PS); | ||
1442 | ieee80211_queue_work(&local->hw, | ||
1443 | &local->dynamic_ps_disable_work); | ||
1444 | } | ||
1445 | |||
1446 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
1447 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | ||
1448 | } | ||
1449 | |||
1450 | rcu_read_lock(); | 1484 | rcu_read_lock(); |
1451 | 1485 | ||
1452 | if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { | 1486 | if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { |
@@ -1511,7 +1545,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
1511 | return; | 1545 | return; |
1512 | } | 1546 | } |
1513 | 1547 | ||
1514 | ieee80211_select_queue(local, skb); | 1548 | ieee80211_set_qos_hdr(local, skb); |
1515 | ieee80211_tx(sdata, skb, false); | 1549 | ieee80211_tx(sdata, skb, false); |
1516 | rcu_read_unlock(); | 1550 | rcu_read_unlock(); |
1517 | } | 1551 | } |
@@ -2060,6 +2094,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2060 | struct beacon_data *beacon; | 2094 | struct beacon_data *beacon; |
2061 | struct ieee80211_supported_band *sband; | 2095 | struct ieee80211_supported_band *sband; |
2062 | enum ieee80211_band band = local->hw.conf.channel->band; | 2096 | enum ieee80211_band band = local->hw.conf.channel->band; |
2097 | struct ieee80211_tx_rate_control txrc; | ||
2063 | 2098 | ||
2064 | sband = local->hw.wiphy->bands[band]; | 2099 | sband = local->hw.wiphy->bands[band]; |
2065 | 2100 | ||
@@ -2167,21 +2202,25 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2167 | info = IEEE80211_SKB_CB(skb); | 2202 | info = IEEE80211_SKB_CB(skb); |
2168 | 2203 | ||
2169 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 2204 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
2205 | info->flags |= IEEE80211_TX_CTL_NO_ACK; | ||
2170 | info->band = band; | 2206 | info->band = band; |
2171 | /* | 2207 | |
2172 | * XXX: For now, always use the lowest rate | 2208 | memset(&txrc, 0, sizeof(txrc)); |
2173 | */ | 2209 | txrc.hw = hw; |
2174 | info->control.rates[0].idx = 0; | 2210 | txrc.sband = sband; |
2175 | info->control.rates[0].count = 1; | 2211 | txrc.bss_conf = &sdata->vif.bss_conf; |
2176 | info->control.rates[1].idx = -1; | 2212 | txrc.skb = skb; |
2177 | info->control.rates[2].idx = -1; | 2213 | txrc.reported_rate.idx = -1; |
2178 | info->control.rates[3].idx = -1; | 2214 | txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; |
2179 | info->control.rates[4].idx = -1; | 2215 | if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1) |
2180 | BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5); | 2216 | txrc.max_rate_idx = -1; |
2217 | else | ||
2218 | txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | ||
2219 | txrc.ap = true; | ||
2220 | rate_control_get_rate(sdata, NULL, &txrc); | ||
2181 | 2221 | ||
2182 | info->control.vif = vif; | 2222 | info->control.vif = vif; |
2183 | 2223 | ||
2184 | info->flags |= IEEE80211_TX_CTL_NO_ACK; | ||
2185 | info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; | 2224 | info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; |
2186 | info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; | 2225 | info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; |
2187 | out: | 2226 | out: |
@@ -2190,6 +2229,134 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2190 | } | 2229 | } |
2191 | EXPORT_SYMBOL(ieee80211_beacon_get_tim); | 2230 | EXPORT_SYMBOL(ieee80211_beacon_get_tim); |
2192 | 2231 | ||
2232 | struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, | ||
2233 | struct ieee80211_vif *vif) | ||
2234 | { | ||
2235 | struct ieee80211_sub_if_data *sdata; | ||
2236 | struct ieee80211_if_managed *ifmgd; | ||
2237 | struct ieee80211_pspoll *pspoll; | ||
2238 | struct ieee80211_local *local; | ||
2239 | struct sk_buff *skb; | ||
2240 | |||
2241 | if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) | ||
2242 | return NULL; | ||
2243 | |||
2244 | sdata = vif_to_sdata(vif); | ||
2245 | ifmgd = &sdata->u.mgd; | ||
2246 | local = sdata->local; | ||
2247 | |||
2248 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll)); | ||
2249 | if (!skb) { | ||
2250 | printk(KERN_DEBUG "%s: failed to allocate buffer for " | ||
2251 | "pspoll template\n", sdata->name); | ||
2252 | return NULL; | ||
2253 | } | ||
2254 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
2255 | |||
2256 | pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll)); | ||
2257 | memset(pspoll, 0, sizeof(*pspoll)); | ||
2258 | pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | ||
2259 | IEEE80211_STYPE_PSPOLL); | ||
2260 | pspoll->aid = cpu_to_le16(ifmgd->aid); | ||
2261 | |||
2262 | /* aid in PS-Poll has its two MSBs each set to 1 */ | ||
2263 | pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); | ||
2264 | |||
2265 | memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN); | ||
2266 | memcpy(pspoll->ta, vif->addr, ETH_ALEN); | ||
2267 | |||
2268 | return skb; | ||
2269 | } | ||
2270 | EXPORT_SYMBOL(ieee80211_pspoll_get); | ||
2271 | |||
2272 | struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, | ||
2273 | struct ieee80211_vif *vif) | ||
2274 | { | ||
2275 | struct ieee80211_hdr_3addr *nullfunc; | ||
2276 | struct ieee80211_sub_if_data *sdata; | ||
2277 | struct ieee80211_if_managed *ifmgd; | ||
2278 | struct ieee80211_local *local; | ||
2279 | struct sk_buff *skb; | ||
2280 | |||
2281 | if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) | ||
2282 | return NULL; | ||
2283 | |||
2284 | sdata = vif_to_sdata(vif); | ||
2285 | ifmgd = &sdata->u.mgd; | ||
2286 | local = sdata->local; | ||
2287 | |||
2288 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*nullfunc)); | ||
2289 | if (!skb) { | ||
2290 | printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " | ||
2291 | "template\n", sdata->name); | ||
2292 | return NULL; | ||
2293 | } | ||
2294 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
2295 | |||
2296 | nullfunc = (struct ieee80211_hdr_3addr *) skb_put(skb, | ||
2297 | sizeof(*nullfunc)); | ||
2298 | memset(nullfunc, 0, sizeof(*nullfunc)); | ||
2299 | nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
2300 | IEEE80211_STYPE_NULLFUNC | | ||
2301 | IEEE80211_FCTL_TODS); | ||
2302 | memcpy(nullfunc->addr1, ifmgd->bssid, ETH_ALEN); | ||
2303 | memcpy(nullfunc->addr2, vif->addr, ETH_ALEN); | ||
2304 | memcpy(nullfunc->addr3, ifmgd->bssid, ETH_ALEN); | ||
2305 | |||
2306 | return skb; | ||
2307 | } | ||
2308 | EXPORT_SYMBOL(ieee80211_nullfunc_get); | ||
2309 | |||
2310 | struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | ||
2311 | struct ieee80211_vif *vif, | ||
2312 | const u8 *ssid, size_t ssid_len, | ||
2313 | const u8 *ie, size_t ie_len) | ||
2314 | { | ||
2315 | struct ieee80211_sub_if_data *sdata; | ||
2316 | struct ieee80211_local *local; | ||
2317 | struct ieee80211_hdr_3addr *hdr; | ||
2318 | struct sk_buff *skb; | ||
2319 | size_t ie_ssid_len; | ||
2320 | u8 *pos; | ||
2321 | |||
2322 | sdata = vif_to_sdata(vif); | ||
2323 | local = sdata->local; | ||
2324 | ie_ssid_len = 2 + ssid_len; | ||
2325 | |||
2326 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) + | ||
2327 | ie_ssid_len + ie_len); | ||
2328 | if (!skb) { | ||
2329 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
2330 | "request template\n", sdata->name); | ||
2331 | return NULL; | ||
2332 | } | ||
2333 | |||
2334 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
2335 | |||
2336 | hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); | ||
2337 | memset(hdr, 0, sizeof(*hdr)); | ||
2338 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
2339 | IEEE80211_STYPE_PROBE_REQ); | ||
2340 | memset(hdr->addr1, 0xff, ETH_ALEN); | ||
2341 | memcpy(hdr->addr2, vif->addr, ETH_ALEN); | ||
2342 | memset(hdr->addr3, 0xff, ETH_ALEN); | ||
2343 | |||
2344 | pos = skb_put(skb, ie_ssid_len); | ||
2345 | *pos++ = WLAN_EID_SSID; | ||
2346 | *pos++ = ssid_len; | ||
2347 | if (ssid) | ||
2348 | memcpy(pos, ssid, ssid_len); | ||
2349 | pos += ssid_len; | ||
2350 | |||
2351 | if (ie) { | ||
2352 | pos = skb_put(skb, ie_len); | ||
2353 | memcpy(pos, ie, ie_len); | ||
2354 | } | ||
2355 | |||
2356 | return skb; | ||
2357 | } | ||
2358 | EXPORT_SYMBOL(ieee80211_probereq_get); | ||
2359 | |||
2193 | void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 2360 | void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
2194 | const void *frame, size_t frame_len, | 2361 | const void *frame, size_t frame_len, |
2195 | const struct ieee80211_tx_info *frame_txctl, | 2362 | const struct ieee80211_tx_info *frame_txctl, |
@@ -2289,6 +2456,9 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
2289 | skb_set_network_header(skb, 0); | 2456 | skb_set_network_header(skb, 0); |
2290 | skb_set_transport_header(skb, 0); | 2457 | skb_set_transport_header(skb, 0); |
2291 | 2458 | ||
2459 | /* send all internal mgmt frames on VO */ | ||
2460 | skb_set_queue_mapping(skb, 0); | ||
2461 | |||
2292 | /* | 2462 | /* |
2293 | * The other path calling ieee80211_xmit is from the tasklet, | 2463 | * The other path calling ieee80211_xmit is from the tasklet, |
2294 | * and while we can handle concurrent transmissions locking | 2464 | * and while we can handle concurrent transmissions locking |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7e38858a9280..ca170b417da6 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/skbuff.h> | 18 | #include <linux/skbuff.h> |
19 | #include <linux/etherdevice.h> | 19 | #include <linux/etherdevice.h> |
20 | #include <linux/if_arp.h> | 20 | #include <linux/if_arp.h> |
21 | #include <linux/wireless.h> | ||
22 | #include <linux/bitmap.h> | 21 | #include <linux/bitmap.h> |
23 | #include <linux/crc32.h> | 22 | #include <linux/crc32.h> |
24 | #include <net/net_namespace.h> | 23 | #include <net/net_namespace.h> |
@@ -269,6 +268,7 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
269 | enum queue_stop_reason reason) | 268 | enum queue_stop_reason reason) |
270 | { | 269 | { |
271 | struct ieee80211_local *local = hw_to_local(hw); | 270 | struct ieee80211_local *local = hw_to_local(hw); |
271 | struct ieee80211_sub_if_data *sdata; | ||
272 | 272 | ||
273 | if (WARN_ON(queue >= hw->queues)) | 273 | if (WARN_ON(queue >= hw->queues)) |
274 | return; | 274 | return; |
@@ -281,6 +281,11 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
281 | 281 | ||
282 | if (!skb_queue_empty(&local->pending[queue])) | 282 | if (!skb_queue_empty(&local->pending[queue])) |
283 | tasklet_schedule(&local->tx_pending_tasklet); | 283 | tasklet_schedule(&local->tx_pending_tasklet); |
284 | |||
285 | rcu_read_lock(); | ||
286 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | ||
287 | netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue)); | ||
288 | rcu_read_unlock(); | ||
284 | } | 289 | } |
285 | 290 | ||
286 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | 291 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, |
@@ -305,11 +310,17 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
305 | enum queue_stop_reason reason) | 310 | enum queue_stop_reason reason) |
306 | { | 311 | { |
307 | struct ieee80211_local *local = hw_to_local(hw); | 312 | struct ieee80211_local *local = hw_to_local(hw); |
313 | struct ieee80211_sub_if_data *sdata; | ||
308 | 314 | ||
309 | if (WARN_ON(queue >= hw->queues)) | 315 | if (WARN_ON(queue >= hw->queues)) |
310 | return; | 316 | return; |
311 | 317 | ||
312 | __set_bit(reason, &local->queue_stop_reasons[queue]); | 318 | __set_bit(reason, &local->queue_stop_reasons[queue]); |
319 | |||
320 | rcu_read_lock(); | ||
321 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | ||
322 | netif_tx_stop_queue(netdev_get_tx_queue(sdata->dev, queue)); | ||
323 | rcu_read_unlock(); | ||
313 | } | 324 | } |
314 | 325 | ||
315 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | 326 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, |
@@ -781,6 +792,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) | |||
781 | break; | 792 | break; |
782 | } | 793 | } |
783 | 794 | ||
795 | qparam.uapsd = false; | ||
796 | |||
784 | drv_conf_tx(local, queue, &qparam); | 797 | drv_conf_tx(local, queue, &qparam); |
785 | } | 798 | } |
786 | } | 799 | } |
@@ -989,40 +1002,33 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
989 | struct ieee80211_local *local = sdata->local; | 1002 | struct ieee80211_local *local = sdata->local; |
990 | struct sk_buff *skb; | 1003 | struct sk_buff *skb; |
991 | struct ieee80211_mgmt *mgmt; | 1004 | struct ieee80211_mgmt *mgmt; |
992 | u8 *pos; | 1005 | size_t buf_len; |
993 | 1006 | u8 *buf; | |
994 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + | 1007 | |
995 | ie_len); | 1008 | /* FIXME: come up with a proper value */ |
996 | if (!skb) { | 1009 | buf = kmalloc(200 + ie_len, GFP_KERNEL); |
997 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | 1010 | if (!buf) { |
998 | "request\n", sdata->name); | 1011 | printk(KERN_DEBUG "%s: failed to allocate temporary IE " |
1012 | "buffer\n", sdata->name); | ||
999 | return; | 1013 | return; |
1000 | } | 1014 | } |
1001 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1002 | 1015 | ||
1003 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 1016 | buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, |
1004 | memset(mgmt, 0, 24); | 1017 | local->hw.conf.channel->band); |
1005 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 1018 | |
1006 | IEEE80211_STYPE_PROBE_REQ); | 1019 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, |
1007 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | 1020 | ssid, ssid_len, |
1021 | buf, buf_len); | ||
1022 | |||
1008 | if (dst) { | 1023 | if (dst) { |
1024 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
1009 | memcpy(mgmt->da, dst, ETH_ALEN); | 1025 | memcpy(mgmt->da, dst, ETH_ALEN); |
1010 | memcpy(mgmt->bssid, dst, ETH_ALEN); | 1026 | memcpy(mgmt->bssid, dst, ETH_ALEN); |
1011 | } else { | ||
1012 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
1013 | memset(mgmt->bssid, 0xff, ETH_ALEN); | ||
1014 | } | 1027 | } |
1015 | pos = skb_put(skb, 2 + ssid_len); | ||
1016 | *pos++ = WLAN_EID_SSID; | ||
1017 | *pos++ = ssid_len; | ||
1018 | memcpy(pos, ssid, ssid_len); | ||
1019 | pos += ssid_len; | ||
1020 | |||
1021 | skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len, | ||
1022 | local->hw.conf.channel->band)); | ||
1023 | 1028 | ||
1024 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 1029 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
1025 | ieee80211_tx_skb(sdata, skb); | 1030 | ieee80211_tx_skb(sdata, skb); |
1031 | kfree(buf); | ||
1026 | } | 1032 | } |
1027 | 1033 | ||
1028 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | 1034 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, |
@@ -1066,9 +1072,9 @@ void ieee80211_stop_device(struct ieee80211_local *local) | |||
1066 | ieee80211_led_radio(local, false); | 1072 | ieee80211_led_radio(local, false); |
1067 | 1073 | ||
1068 | cancel_work_sync(&local->reconfig_filter); | 1074 | cancel_work_sync(&local->reconfig_filter); |
1069 | drv_stop(local); | ||
1070 | 1075 | ||
1071 | flush_workqueue(local->workqueue); | 1076 | flush_workqueue(local->workqueue); |
1077 | drv_stop(local); | ||
1072 | } | 1078 | } |
1073 | 1079 | ||
1074 | int ieee80211_reconfig(struct ieee80211_local *local) | 1080 | int ieee80211_reconfig(struct ieee80211_local *local) |
@@ -1094,7 +1100,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1094 | if (res) { | 1100 | if (res) { |
1095 | WARN(local->suspended, "Harware became unavailable " | 1101 | WARN(local->suspended, "Harware became unavailable " |
1096 | "upon resume. This is could be a software issue" | 1102 | "upon resume. This is could be a software issue" |
1097 | "prior to suspend or a harware issue\n"); | 1103 | "prior to suspend or a hardware issue\n"); |
1098 | return res; | 1104 | return res; |
1099 | } | 1105 | } |
1100 | 1106 | ||
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index b19b7696f3a2..34e6d02da779 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -44,22 +44,69 @@ static int wme_downgrade_ac(struct sk_buff *skb) | |||
44 | } | 44 | } |
45 | 45 | ||
46 | 46 | ||
47 | /* Indicate which queue to use. */ | 47 | /* Indicate which queue to use. */ |
48 | static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb) | 48 | u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, |
49 | struct sk_buff *skb) | ||
49 | { | 50 | { |
50 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 51 | struct ieee80211_local *local = sdata->local; |
52 | struct sta_info *sta = NULL; | ||
53 | u32 sta_flags = 0; | ||
54 | const u8 *ra = NULL; | ||
55 | bool qos = false; | ||
51 | 56 | ||
52 | if (!ieee80211_is_data(hdr->frame_control)) { | 57 | if (local->hw.queues < 4 || skb->len < 6) { |
53 | /* management frames go on AC_VO queue, but are sent | 58 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
54 | * without QoS control fields */ | 59 | return min_t(u16, local->hw.queues - 1, |
55 | return 0; | 60 | ieee802_1d_to_ac[skb->priority]); |
61 | } | ||
62 | |||
63 | rcu_read_lock(); | ||
64 | switch (sdata->vif.type) { | ||
65 | case NL80211_IFTYPE_AP_VLAN: | ||
66 | rcu_read_lock(); | ||
67 | sta = rcu_dereference(sdata->u.vlan.sta); | ||
68 | if (sta) | ||
69 | sta_flags = get_sta_flags(sta); | ||
70 | rcu_read_unlock(); | ||
71 | if (sta) | ||
72 | break; | ||
73 | case NL80211_IFTYPE_AP: | ||
74 | ra = skb->data; | ||
75 | break; | ||
76 | case NL80211_IFTYPE_WDS: | ||
77 | ra = sdata->u.wds.remote_addr; | ||
78 | break; | ||
79 | #ifdef CONFIG_MAC80211_MESH | ||
80 | case NL80211_IFTYPE_MESH_POINT: | ||
81 | /* | ||
82 | * XXX: This is clearly broken ... but already was before, | ||
83 | * because ieee80211_fill_mesh_addresses() would clear A1 | ||
84 | * except for multicast addresses. | ||
85 | */ | ||
86 | break; | ||
87 | #endif | ||
88 | case NL80211_IFTYPE_STATION: | ||
89 | ra = sdata->u.mgd.bssid; | ||
90 | break; | ||
91 | case NL80211_IFTYPE_ADHOC: | ||
92 | ra = skb->data; | ||
93 | break; | ||
94 | default: | ||
95 | break; | ||
56 | } | 96 | } |
57 | 97 | ||
58 | if (0 /* injected */) { | 98 | if (!sta && ra && !is_multicast_ether_addr(ra)) { |
59 | /* use AC from radiotap */ | 99 | sta = sta_info_get(sdata, ra); |
100 | if (sta) | ||
101 | sta_flags = get_sta_flags(sta); | ||
60 | } | 102 | } |
61 | 103 | ||
62 | if (!ieee80211_is_data_qos(hdr->frame_control)) { | 104 | if (sta_flags & WLAN_STA_WME) |
105 | qos = true; | ||
106 | |||
107 | rcu_read_unlock(); | ||
108 | |||
109 | if (!qos) { | ||
63 | skb->priority = 0; /* required for correct WPA/11i MIC */ | 110 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
64 | return ieee802_1d_to_ac[skb->priority]; | 111 | return ieee802_1d_to_ac[skb->priority]; |
65 | } | 112 | } |
@@ -68,6 +115,12 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb) | |||
68 | * data frame has */ | 115 | * data frame has */ |
69 | skb->priority = cfg80211_classify8021d(skb); | 116 | skb->priority = cfg80211_classify8021d(skb); |
70 | 117 | ||
118 | return ieee80211_downgrade_queue(local, skb); | ||
119 | } | ||
120 | |||
121 | u16 ieee80211_downgrade_queue(struct ieee80211_local *local, | ||
122 | struct sk_buff *skb) | ||
123 | { | ||
71 | /* in case we are a client verify acm is not set for this ac */ | 124 | /* in case we are a client verify acm is not set for this ac */ |
72 | while (unlikely(local->wmm_acm & BIT(skb->priority))) { | 125 | while (unlikely(local->wmm_acm & BIT(skb->priority))) { |
73 | if (wme_downgrade_ac(skb)) { | 126 | if (wme_downgrade_ac(skb)) { |
@@ -85,24 +138,17 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb) | |||
85 | return ieee802_1d_to_ac[skb->priority]; | 138 | return ieee802_1d_to_ac[skb->priority]; |
86 | } | 139 | } |
87 | 140 | ||
88 | void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb) | 141 | void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb) |
89 | { | 142 | { |
90 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 143 | struct ieee80211_hdr *hdr = (void *)skb->data; |
91 | u16 queue; | 144 | |
92 | u8 tid; | 145 | /* Fill in the QoS header if there is one. */ |
93 | |||
94 | queue = classify80211(local, skb); | ||
95 | if (unlikely(queue >= local->hw.queues)) | ||
96 | queue = local->hw.queues - 1; | ||
97 | |||
98 | /* | ||
99 | * Now we know the 1d priority, fill in the QoS header if | ||
100 | * there is one (and we haven't done this before). | ||
101 | */ | ||
102 | if (ieee80211_is_data_qos(hdr->frame_control)) { | 146 | if (ieee80211_is_data_qos(hdr->frame_control)) { |
103 | u8 *p = ieee80211_get_qos_ctl(hdr); | 147 | u8 *p = ieee80211_get_qos_ctl(hdr); |
104 | u8 ack_policy = 0; | 148 | u8 ack_policy = 0, tid; |
149 | |||
105 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; | 150 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; |
151 | |||
106 | if (unlikely(local->wifi_wme_noack_test)) | 152 | if (unlikely(local->wifi_wme_noack_test)) |
107 | ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK << | 153 | ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK << |
108 | QOS_CONTROL_ACK_POLICY_SHIFT; | 154 | QOS_CONTROL_ACK_POLICY_SHIFT; |
@@ -110,6 +156,4 @@ void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb) | |||
110 | *p++ = ack_policy | tid; | 156 | *p++ = ack_policy | tid; |
111 | *p = 0; | 157 | *p = 0; |
112 | } | 158 | } |
113 | |||
114 | skb_set_queue_mapping(skb, queue); | ||
115 | } | 159 | } |
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index d4fd87ca5118..6053b1c9feee 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h | |||
@@ -20,7 +20,11 @@ | |||
20 | 20 | ||
21 | extern const int ieee802_1d_to_ac[8]; | 21 | extern const int ieee802_1d_to_ac[8]; |
22 | 22 | ||
23 | void ieee80211_select_queue(struct ieee80211_local *local, | 23 | u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, |
24 | struct sk_buff *skb); | 24 | struct sk_buff *skb); |
25 | void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb); | ||
26 | u16 ieee80211_downgrade_queue(struct ieee80211_local *local, | ||
27 | struct sk_buff *skb); | ||
28 | |||
25 | 29 | ||
26 | #endif /* _WME_H */ | 30 | #endif /* _WME_H */ |
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index ea89ed70734d..81bd5d592bb4 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
@@ -202,7 +202,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
202 | struct ieee80211_local *local = sdata->local; | 202 | struct ieee80211_local *local = sdata->local; |
203 | struct sk_buff *skb; | 203 | struct sk_buff *skb; |
204 | struct ieee80211_mgmt *mgmt; | 204 | struct ieee80211_mgmt *mgmt; |
205 | u8 *pos; | 205 | u8 *pos, qos_info; |
206 | const u8 *ies; | 206 | const u8 *ies; |
207 | size_t offset = 0, noffset; | 207 | size_t offset = 0, noffset; |
208 | int i, len, count, rates_len, supp_rates_len; | 208 | int i, len, count, rates_len, supp_rates_len; |
@@ -375,6 +375,14 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
375 | } | 375 | } |
376 | 376 | ||
377 | if (wk->assoc.wmm_used && local->hw.queues >= 4) { | 377 | if (wk->assoc.wmm_used && local->hw.queues >= 4) { |
378 | if (wk->assoc.uapsd_used) { | ||
379 | qos_info = local->uapsd_queues; | ||
380 | qos_info |= (local->uapsd_max_sp_len << | ||
381 | IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT); | ||
382 | } else { | ||
383 | qos_info = 0; | ||
384 | } | ||
385 | |||
378 | pos = skb_put(skb, 9); | 386 | pos = skb_put(skb, 9); |
379 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | 387 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; |
380 | *pos++ = 7; /* len */ | 388 | *pos++ = 7; /* len */ |
@@ -384,7 +392,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
384 | *pos++ = 2; /* WME */ | 392 | *pos++ = 2; /* WME */ |
385 | *pos++ = 0; /* WME info */ | 393 | *pos++ = 0; /* WME info */ |
386 | *pos++ = 1; /* WME ver */ | 394 | *pos++ = 1; /* WME ver */ |
387 | *pos++ = 0; | 395 | *pos++ = qos_info; |
388 | } | 396 | } |
389 | 397 | ||
390 | /* add any remaining custom (i.e. vendor specific here) IEs */ | 398 | /* add any remaining custom (i.e. vendor specific here) IEs */ |
@@ -531,9 +539,9 @@ ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) | |||
531 | wk->remain.started = true; | 539 | wk->remain.started = true; |
532 | wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration); | 540 | wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration); |
533 | 541 | ||
534 | cfg80211_ready_on_channel(wk->sdata->dev, (u64)wk, wk->chan, | 542 | cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk, |
535 | wk->chan_type, wk->remain.duration, | 543 | wk->chan, wk->chan_type, |
536 | GFP_KERNEL); | 544 | wk->remain.duration, GFP_KERNEL); |
537 | 545 | ||
538 | return WORK_ACT_NONE; | 546 | return WORK_ACT_NONE; |
539 | } | 547 | } |
@@ -818,6 +826,7 @@ static void ieee80211_work_work(struct work_struct *work) | |||
818 | wk->chan == local->tmp_channel && | 826 | wk->chan == local->tmp_channel && |
819 | wk->chan_type == local->tmp_channel_type) { | 827 | wk->chan_type == local->tmp_channel_type) { |
820 | wk->started = true; | 828 | wk->started = true; |
829 | wk->timeout = jiffies; | ||
821 | } | 830 | } |
822 | 831 | ||
823 | if (!wk->started && !local->tmp_channel) { | 832 | if (!wk->started && !local->tmp_channel) { |
@@ -935,6 +944,9 @@ void ieee80211_add_work(struct ieee80211_work *wk) | |||
935 | if (WARN_ON(!wk->done)) | 944 | if (WARN_ON(!wk->done)) |
936 | return; | 945 | return; |
937 | 946 | ||
947 | if (WARN_ON(!ieee80211_sdata_running(wk->sdata))) | ||
948 | return; | ||
949 | |||
938 | wk->started = false; | 950 | wk->started = false; |
939 | 951 | ||
940 | local = wk->sdata->local; | 952 | local = wk->sdata->local; |
@@ -1027,7 +1039,7 @@ static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk, | |||
1027 | /* | 1039 | /* |
1028 | * We are done serving the remain-on-channel command. | 1040 | * We are done serving the remain-on-channel command. |
1029 | */ | 1041 | */ |
1030 | cfg80211_remain_on_channel_expired(wk->sdata->dev, (u64)wk, | 1042 | cfg80211_remain_on_channel_expired(wk->sdata->dev, (unsigned long) wk, |
1031 | wk->chan, wk->chan_type, | 1043 | wk->chan, wk->chan_type, |
1032 | GFP_KERNEL); | 1044 | GFP_KERNEL); |
1033 | 1045 | ||
@@ -1053,7 +1065,7 @@ int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, | |||
1053 | 1065 | ||
1054 | wk->remain.duration = duration; | 1066 | wk->remain.duration = duration; |
1055 | 1067 | ||
1056 | *cookie = (u64)wk; | 1068 | *cookie = (unsigned long) wk; |
1057 | 1069 | ||
1058 | ieee80211_add_work(wk); | 1070 | ieee80211_add_work(wk); |
1059 | 1071 | ||
@@ -1069,7 +1081,7 @@ int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata, | |||
1069 | 1081 | ||
1070 | mutex_lock(&local->work_mtx); | 1082 | mutex_lock(&local->work_mtx); |
1071 | list_for_each_entry_safe(wk, tmp, &local->work_list, list) { | 1083 | list_for_each_entry_safe(wk, tmp, &local->work_list, list) { |
1072 | if ((u64)wk == cookie) { | 1084 | if ((unsigned long) wk == cookie) { |
1073 | wk->timeout = jiffies; | 1085 | wk->timeout = jiffies; |
1074 | found = true; | 1086 | found = true; |
1075 | break; | 1087 | break; |
diff --git a/net/wireless/core.c b/net/wireless/core.c index c2a2c563d21a..0a545bb6ed05 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -402,6 +402,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
402 | rdev->wiphy.retry_long = 4; | 402 | rdev->wiphy.retry_long = 4; |
403 | rdev->wiphy.frag_threshold = (u32) -1; | 403 | rdev->wiphy.frag_threshold = (u32) -1; |
404 | rdev->wiphy.rts_threshold = (u32) -1; | 404 | rdev->wiphy.rts_threshold = (u32) -1; |
405 | rdev->wiphy.coverage_class = 0; | ||
405 | 406 | ||
406 | return &rdev->wiphy; | 407 | return &rdev->wiphy; |
407 | } | 408 | } |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 30ec95f05b52..2d6a6b9c0c43 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -111,7 +111,8 @@ struct cfg80211_internal_bss { | |||
111 | unsigned long ts; | 111 | unsigned long ts; |
112 | struct kref ref; | 112 | struct kref ref; |
113 | atomic_t hold; | 113 | atomic_t hold; |
114 | bool ies_allocated; | 114 | bool beacon_ies_allocated; |
115 | bool proberesp_ies_allocated; | ||
115 | 116 | ||
116 | /* must be last because of priv member */ | 117 | /* must be last because of priv member */ |
117 | struct cfg80211_bss pub; | 118 | struct cfg80211_bss pub; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e3bee3cecdfa..4af7991a9ec8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -69,6 +69,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
69 | [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, | 69 | [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, |
70 | [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, | 70 | [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, |
71 | [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 }, | 71 | [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 }, |
72 | [NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 }, | ||
72 | 73 | ||
73 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, | 74 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, |
74 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, | 75 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, |
@@ -143,6 +144,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
143 | .len = WLAN_PMKID_LEN }, | 144 | .len = WLAN_PMKID_LEN }, |
144 | [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, | 145 | [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, |
145 | [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, | 146 | [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, |
147 | [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED }, | ||
146 | }; | 148 | }; |
147 | 149 | ||
148 | /* policy for the attributes */ | 150 | /* policy for the attributes */ |
@@ -444,6 +446,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
444 | dev->wiphy.frag_threshold); | 446 | dev->wiphy.frag_threshold); |
445 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, | 447 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, |
446 | dev->wiphy.rts_threshold); | 448 | dev->wiphy.rts_threshold); |
449 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, | ||
450 | dev->wiphy.coverage_class); | ||
447 | 451 | ||
448 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | 452 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, |
449 | dev->wiphy.max_scan_ssids); | 453 | dev->wiphy.max_scan_ssids); |
@@ -572,6 +576,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
572 | CMD(del_pmksa, DEL_PMKSA); | 576 | CMD(del_pmksa, DEL_PMKSA); |
573 | CMD(flush_pmksa, FLUSH_PMKSA); | 577 | CMD(flush_pmksa, FLUSH_PMKSA); |
574 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | 578 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); |
579 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); | ||
575 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | 580 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { |
576 | i++; | 581 | i++; |
577 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); | 582 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); |
@@ -684,6 +689,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
684 | u32 changed; | 689 | u32 changed; |
685 | u8 retry_short = 0, retry_long = 0; | 690 | u8 retry_short = 0, retry_long = 0; |
686 | u32 frag_threshold = 0, rts_threshold = 0; | 691 | u32 frag_threshold = 0, rts_threshold = 0; |
692 | u8 coverage_class = 0; | ||
687 | 693 | ||
688 | rtnl_lock(); | 694 | rtnl_lock(); |
689 | 695 | ||
@@ -806,9 +812,16 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
806 | changed |= WIPHY_PARAM_RTS_THRESHOLD; | 812 | changed |= WIPHY_PARAM_RTS_THRESHOLD; |
807 | } | 813 | } |
808 | 814 | ||
815 | if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) { | ||
816 | coverage_class = nla_get_u8( | ||
817 | info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]); | ||
818 | changed |= WIPHY_PARAM_COVERAGE_CLASS; | ||
819 | } | ||
820 | |||
809 | if (changed) { | 821 | if (changed) { |
810 | u8 old_retry_short, old_retry_long; | 822 | u8 old_retry_short, old_retry_long; |
811 | u32 old_frag_threshold, old_rts_threshold; | 823 | u32 old_frag_threshold, old_rts_threshold; |
824 | u8 old_coverage_class; | ||
812 | 825 | ||
813 | if (!rdev->ops->set_wiphy_params) { | 826 | if (!rdev->ops->set_wiphy_params) { |
814 | result = -EOPNOTSUPP; | 827 | result = -EOPNOTSUPP; |
@@ -819,6 +832,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
819 | old_retry_long = rdev->wiphy.retry_long; | 832 | old_retry_long = rdev->wiphy.retry_long; |
820 | old_frag_threshold = rdev->wiphy.frag_threshold; | 833 | old_frag_threshold = rdev->wiphy.frag_threshold; |
821 | old_rts_threshold = rdev->wiphy.rts_threshold; | 834 | old_rts_threshold = rdev->wiphy.rts_threshold; |
835 | old_coverage_class = rdev->wiphy.coverage_class; | ||
822 | 836 | ||
823 | if (changed & WIPHY_PARAM_RETRY_SHORT) | 837 | if (changed & WIPHY_PARAM_RETRY_SHORT) |
824 | rdev->wiphy.retry_short = retry_short; | 838 | rdev->wiphy.retry_short = retry_short; |
@@ -828,6 +842,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
828 | rdev->wiphy.frag_threshold = frag_threshold; | 842 | rdev->wiphy.frag_threshold = frag_threshold; |
829 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) | 843 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) |
830 | rdev->wiphy.rts_threshold = rts_threshold; | 844 | rdev->wiphy.rts_threshold = rts_threshold; |
845 | if (changed & WIPHY_PARAM_COVERAGE_CLASS) | ||
846 | rdev->wiphy.coverage_class = coverage_class; | ||
831 | 847 | ||
832 | result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); | 848 | result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); |
833 | if (result) { | 849 | if (result) { |
@@ -835,6 +851,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
835 | rdev->wiphy.retry_long = old_retry_long; | 851 | rdev->wiphy.retry_long = old_retry_long; |
836 | rdev->wiphy.frag_threshold = old_frag_threshold; | 852 | rdev->wiphy.frag_threshold = old_frag_threshold; |
837 | rdev->wiphy.rts_threshold = old_rts_threshold; | 853 | rdev->wiphy.rts_threshold = old_rts_threshold; |
854 | rdev->wiphy.coverage_class = old_coverage_class; | ||
838 | } | 855 | } |
839 | } | 856 | } |
840 | 857 | ||
@@ -3146,6 +3163,10 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
3146 | NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS, | 3163 | NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS, |
3147 | res->len_information_elements, | 3164 | res->len_information_elements, |
3148 | res->information_elements); | 3165 | res->information_elements); |
3166 | if (res->beacon_ies && res->len_beacon_ies && | ||
3167 | res->beacon_ies != res->information_elements) | ||
3168 | NLA_PUT(msg, NL80211_BSS_BEACON_IES, | ||
3169 | res->len_beacon_ies, res->beacon_ies); | ||
3149 | if (res->tsf) | 3170 | if (res->tsf) |
3150 | NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf); | 3171 | NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf); |
3151 | if (res->beacon_interval) | 3172 | if (res->beacon_interval) |
@@ -4423,6 +4444,109 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | |||
4423 | return err; | 4444 | return err; |
4424 | } | 4445 | } |
4425 | 4446 | ||
4447 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, | ||
4448 | u8 *rates, u8 rates_len) | ||
4449 | { | ||
4450 | u8 i; | ||
4451 | u32 mask = 0; | ||
4452 | |||
4453 | for (i = 0; i < rates_len; i++) { | ||
4454 | int rate = (rates[i] & 0x7f) * 5; | ||
4455 | int ridx; | ||
4456 | for (ridx = 0; ridx < sband->n_bitrates; ridx++) { | ||
4457 | struct ieee80211_rate *srate = | ||
4458 | &sband->bitrates[ridx]; | ||
4459 | if (rate == srate->bitrate) { | ||
4460 | mask |= 1 << ridx; | ||
4461 | break; | ||
4462 | } | ||
4463 | } | ||
4464 | if (ridx == sband->n_bitrates) | ||
4465 | return 0; /* rate not found */ | ||
4466 | } | ||
4467 | |||
4468 | return mask; | ||
4469 | } | ||
4470 | |||
4471 | static struct nla_policy | ||
4472 | nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] __read_mostly = { | ||
4473 | [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, | ||
4474 | .len = NL80211_MAX_SUPP_RATES }, | ||
4475 | }; | ||
4476 | |||
4477 | static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | ||
4478 | struct genl_info *info) | ||
4479 | { | ||
4480 | struct nlattr *tb[NL80211_TXRATE_MAX + 1]; | ||
4481 | struct cfg80211_registered_device *rdev; | ||
4482 | struct cfg80211_bitrate_mask mask; | ||
4483 | int err, rem, i; | ||
4484 | struct net_device *dev; | ||
4485 | struct nlattr *tx_rates; | ||
4486 | struct ieee80211_supported_band *sband; | ||
4487 | |||
4488 | if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) | ||
4489 | return -EINVAL; | ||
4490 | |||
4491 | rtnl_lock(); | ||
4492 | |||
4493 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4494 | if (err) | ||
4495 | goto unlock_rtnl; | ||
4496 | |||
4497 | if (!rdev->ops->set_bitrate_mask) { | ||
4498 | err = -EOPNOTSUPP; | ||
4499 | goto unlock; | ||
4500 | } | ||
4501 | |||
4502 | memset(&mask, 0, sizeof(mask)); | ||
4503 | /* Default to all rates enabled */ | ||
4504 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | ||
4505 | sband = rdev->wiphy.bands[i]; | ||
4506 | mask.control[i].legacy = | ||
4507 | sband ? (1 << sband->n_bitrates) - 1 : 0; | ||
4508 | } | ||
4509 | |||
4510 | /* | ||
4511 | * The nested attribute uses enum nl80211_band as the index. This maps | ||
4512 | * directly to the enum ieee80211_band values used in cfg80211. | ||
4513 | */ | ||
4514 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) | ||
4515 | { | ||
4516 | enum ieee80211_band band = nla_type(tx_rates); | ||
4517 | if (band < 0 || band >= IEEE80211_NUM_BANDS) { | ||
4518 | err = -EINVAL; | ||
4519 | goto unlock; | ||
4520 | } | ||
4521 | sband = rdev->wiphy.bands[band]; | ||
4522 | if (sband == NULL) { | ||
4523 | err = -EINVAL; | ||
4524 | goto unlock; | ||
4525 | } | ||
4526 | nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), | ||
4527 | nla_len(tx_rates), nl80211_txattr_policy); | ||
4528 | if (tb[NL80211_TXRATE_LEGACY]) { | ||
4529 | mask.control[band].legacy = rateset_to_mask( | ||
4530 | sband, | ||
4531 | nla_data(tb[NL80211_TXRATE_LEGACY]), | ||
4532 | nla_len(tb[NL80211_TXRATE_LEGACY])); | ||
4533 | if (mask.control[band].legacy == 0) { | ||
4534 | err = -EINVAL; | ||
4535 | goto unlock; | ||
4536 | } | ||
4537 | } | ||
4538 | } | ||
4539 | |||
4540 | err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); | ||
4541 | |||
4542 | unlock: | ||
4543 | dev_put(dev); | ||
4544 | cfg80211_unlock_rdev(rdev); | ||
4545 | unlock_rtnl: | ||
4546 | rtnl_unlock(); | ||
4547 | return err; | ||
4548 | } | ||
4549 | |||
4426 | static struct genl_ops nl80211_ops[] = { | 4550 | static struct genl_ops nl80211_ops[] = { |
4427 | { | 4551 | { |
4428 | .cmd = NL80211_CMD_GET_WIPHY, | 4552 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -4697,6 +4821,12 @@ static struct genl_ops nl80211_ops[] = { | |||
4697 | .policy = nl80211_policy, | 4821 | .policy = nl80211_policy, |
4698 | .flags = GENL_ADMIN_PERM, | 4822 | .flags = GENL_ADMIN_PERM, |
4699 | }, | 4823 | }, |
4824 | { | ||
4825 | .cmd = NL80211_CMD_SET_TX_BITRATE_MASK, | ||
4826 | .doit = nl80211_set_tx_bitrate_mask, | ||
4827 | .policy = nl80211_policy, | ||
4828 | .flags = GENL_ADMIN_PERM, | ||
4829 | }, | ||
4700 | }; | 4830 | }; |
4701 | 4831 | ||
4702 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 4832 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 87ea60d84c3c..5f8071de7950 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -43,6 +43,15 @@ | |||
43 | #include "regdb.h" | 43 | #include "regdb.h" |
44 | #include "nl80211.h" | 44 | #include "nl80211.h" |
45 | 45 | ||
46 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
47 | #define REG_DBG_PRINT(format, args...) \ | ||
48 | do { \ | ||
49 | printk(KERN_DEBUG format , ## args); \ | ||
50 | } while (0) | ||
51 | #else | ||
52 | #define REG_DBG_PRINT(args...) | ||
53 | #endif | ||
54 | |||
46 | /* Receipt of information from last regulatory request */ | 55 | /* Receipt of information from last regulatory request */ |
47 | static struct regulatory_request *last_request; | 56 | static struct regulatory_request *last_request; |
48 | 57 | ||
@@ -476,12 +485,212 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, | |||
476 | } | 485 | } |
477 | 486 | ||
478 | /* | 487 | /* |
488 | * This is a work around for sanity checking ieee80211_channel_to_frequency()'s | ||
489 | * work. ieee80211_channel_to_frequency() can for example currently provide a | ||
490 | * 2 GHz channel when in fact a 5 GHz channel was desired. An example would be | ||
491 | * an AP providing channel 8 on a country IE triplet when it sent this on the | ||
492 | * 5 GHz band, that channel is designed to be channel 8 on 5 GHz, not a 2 GHz | ||
493 | * channel. | ||
494 | * | ||
495 | * This can be removed once ieee80211_channel_to_frequency() takes in a band. | ||
496 | */ | ||
497 | static bool chan_in_band(int chan, enum ieee80211_band band) | ||
498 | { | ||
499 | int center_freq = ieee80211_channel_to_frequency(chan); | ||
500 | |||
501 | switch (band) { | ||
502 | case IEEE80211_BAND_2GHZ: | ||
503 | if (center_freq <= 2484) | ||
504 | return true; | ||
505 | return false; | ||
506 | case IEEE80211_BAND_5GHZ: | ||
507 | if (center_freq >= 5005) | ||
508 | return true; | ||
509 | return false; | ||
510 | default: | ||
511 | return false; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | /* | ||
516 | * Some APs may send a country IE triplet for each channel they | ||
517 | * support and while this is completely overkill and silly we still | ||
518 | * need to support it. We avoid making a single rule for each channel | ||
519 | * though and to help us with this we use this helper to find the | ||
520 | * actual subband end channel. These type of country IE triplet | ||
521 | * scenerios are handled then, all yielding two regulaotry rules from | ||
522 | * parsing a country IE: | ||
523 | * | ||
524 | * [1] | ||
525 | * [2] | ||
526 | * [36] | ||
527 | * [40] | ||
528 | * | ||
529 | * [1] | ||
530 | * [2-4] | ||
531 | * [5-12] | ||
532 | * [36] | ||
533 | * [40-44] | ||
534 | * | ||
535 | * [1-4] | ||
536 | * [5-7] | ||
537 | * [36-44] | ||
538 | * [48-64] | ||
539 | * | ||
540 | * [36-36] | ||
541 | * [40-40] | ||
542 | * [44-44] | ||
543 | * [48-48] | ||
544 | * [52-52] | ||
545 | * [56-56] | ||
546 | * [60-60] | ||
547 | * [64-64] | ||
548 | * [100-100] | ||
549 | * [104-104] | ||
550 | * [108-108] | ||
551 | * [112-112] | ||
552 | * [116-116] | ||
553 | * [120-120] | ||
554 | * [124-124] | ||
555 | * [128-128] | ||
556 | * [132-132] | ||
557 | * [136-136] | ||
558 | * [140-140] | ||
559 | * | ||
560 | * Returns 0 if the IE has been found to be invalid in the middle | ||
561 | * somewhere. | ||
562 | */ | ||
563 | static int max_subband_chan(enum ieee80211_band band, | ||
564 | int orig_cur_chan, | ||
565 | int orig_end_channel, | ||
566 | s8 orig_max_power, | ||
567 | u8 **country_ie, | ||
568 | u8 *country_ie_len) | ||
569 | { | ||
570 | u8 *triplets_start = *country_ie; | ||
571 | u8 len_at_triplet = *country_ie_len; | ||
572 | int end_subband_chan = orig_end_channel; | ||
573 | |||
574 | /* | ||
575 | * We'll deal with padding for the caller unless | ||
576 | * its not immediate and we don't process any channels | ||
577 | */ | ||
578 | if (*country_ie_len == 1) { | ||
579 | *country_ie += 1; | ||
580 | *country_ie_len -= 1; | ||
581 | return orig_end_channel; | ||
582 | } | ||
583 | |||
584 | /* Move to the next triplet and then start search */ | ||
585 | *country_ie += 3; | ||
586 | *country_ie_len -= 3; | ||
587 | |||
588 | if (!chan_in_band(orig_cur_chan, band)) | ||
589 | return 0; | ||
590 | |||
591 | while (*country_ie_len >= 3) { | ||
592 | int end_channel = 0; | ||
593 | struct ieee80211_country_ie_triplet *triplet = | ||
594 | (struct ieee80211_country_ie_triplet *) *country_ie; | ||
595 | int cur_channel = 0, next_expected_chan; | ||
596 | |||
597 | /* means last triplet is completely unrelated to this one */ | ||
598 | if (triplet->ext.reg_extension_id >= | ||
599 | IEEE80211_COUNTRY_EXTENSION_ID) { | ||
600 | *country_ie -= 3; | ||
601 | *country_ie_len += 3; | ||
602 | break; | ||
603 | } | ||
604 | |||
605 | if (triplet->chans.first_channel == 0) { | ||
606 | *country_ie += 1; | ||
607 | *country_ie_len -= 1; | ||
608 | if (*country_ie_len != 0) | ||
609 | return 0; | ||
610 | break; | ||
611 | } | ||
612 | |||
613 | if (triplet->chans.num_channels == 0) | ||
614 | return 0; | ||
615 | |||
616 | /* Monitonically increasing channel order */ | ||
617 | if (triplet->chans.first_channel <= end_subband_chan) | ||
618 | return 0; | ||
619 | |||
620 | if (!chan_in_band(triplet->chans.first_channel, band)) | ||
621 | return 0; | ||
622 | |||
623 | /* 2 GHz */ | ||
624 | if (triplet->chans.first_channel <= 14) { | ||
625 | end_channel = triplet->chans.first_channel + | ||
626 | triplet->chans.num_channels - 1; | ||
627 | } | ||
628 | else { | ||
629 | end_channel = triplet->chans.first_channel + | ||
630 | (4 * (triplet->chans.num_channels - 1)); | ||
631 | } | ||
632 | |||
633 | if (!chan_in_band(end_channel, band)) | ||
634 | return 0; | ||
635 | |||
636 | if (orig_max_power != triplet->chans.max_power) { | ||
637 | *country_ie -= 3; | ||
638 | *country_ie_len += 3; | ||
639 | break; | ||
640 | } | ||
641 | |||
642 | cur_channel = triplet->chans.first_channel; | ||
643 | |||
644 | /* The key is finding the right next expected channel */ | ||
645 | if (band == IEEE80211_BAND_2GHZ) | ||
646 | next_expected_chan = end_subband_chan + 1; | ||
647 | else | ||
648 | next_expected_chan = end_subband_chan + 4; | ||
649 | |||
650 | if (cur_channel != next_expected_chan) { | ||
651 | *country_ie -= 3; | ||
652 | *country_ie_len += 3; | ||
653 | break; | ||
654 | } | ||
655 | |||
656 | end_subband_chan = end_channel; | ||
657 | |||
658 | /* Move to the next one */ | ||
659 | *country_ie += 3; | ||
660 | *country_ie_len -= 3; | ||
661 | |||
662 | /* | ||
663 | * Padding needs to be dealt with if we processed | ||
664 | * some channels. | ||
665 | */ | ||
666 | if (*country_ie_len == 1) { | ||
667 | *country_ie += 1; | ||
668 | *country_ie_len -= 1; | ||
669 | break; | ||
670 | } | ||
671 | |||
672 | /* If seen, the IE is invalid */ | ||
673 | if (*country_ie_len == 2) | ||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | if (end_subband_chan == orig_end_channel) { | ||
678 | *country_ie = triplets_start; | ||
679 | *country_ie_len = len_at_triplet; | ||
680 | return orig_end_channel; | ||
681 | } | ||
682 | |||
683 | return end_subband_chan; | ||
684 | } | ||
685 | |||
686 | /* | ||
479 | * Converts a country IE to a regulatory domain. A regulatory domain | 687 | * Converts a country IE to a regulatory domain. A regulatory domain |
480 | * structure has a lot of information which the IE doesn't yet have, | 688 | * structure has a lot of information which the IE doesn't yet have, |
481 | * so for the other values we use upper max values as we will intersect | 689 | * so for the other values we use upper max values as we will intersect |
482 | * with our userspace regulatory agent to get lower bounds. | 690 | * with our userspace regulatory agent to get lower bounds. |
483 | */ | 691 | */ |
484 | static struct ieee80211_regdomain *country_ie_2_rd( | 692 | static struct ieee80211_regdomain *country_ie_2_rd( |
693 | enum ieee80211_band band, | ||
485 | u8 *country_ie, | 694 | u8 *country_ie, |
486 | u8 country_ie_len, | 695 | u8 country_ie_len, |
487 | u32 *checksum) | 696 | u32 *checksum) |
@@ -543,10 +752,29 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
543 | continue; | 752 | continue; |
544 | } | 753 | } |
545 | 754 | ||
755 | /* | ||
756 | * APs can add padding to make length divisible | ||
757 | * by two, required by the spec. | ||
758 | */ | ||
759 | if (triplet->chans.first_channel == 0) { | ||
760 | country_ie++; | ||
761 | country_ie_len--; | ||
762 | /* This is expected to be at the very end only */ | ||
763 | if (country_ie_len != 0) | ||
764 | return NULL; | ||
765 | break; | ||
766 | } | ||
767 | |||
768 | if (triplet->chans.num_channels == 0) | ||
769 | return NULL; | ||
770 | |||
771 | if (!chan_in_band(triplet->chans.first_channel, band)) | ||
772 | return NULL; | ||
773 | |||
546 | /* 2 GHz */ | 774 | /* 2 GHz */ |
547 | if (triplet->chans.first_channel <= 14) | 775 | if (band == IEEE80211_BAND_2GHZ) |
548 | end_channel = triplet->chans.first_channel + | 776 | end_channel = triplet->chans.first_channel + |
549 | triplet->chans.num_channels; | 777 | triplet->chans.num_channels - 1; |
550 | else | 778 | else |
551 | /* | 779 | /* |
552 | * 5 GHz -- For example in country IEs if the first | 780 | * 5 GHz -- For example in country IEs if the first |
@@ -561,6 +789,24 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
561 | (4 * (triplet->chans.num_channels - 1)); | 789 | (4 * (triplet->chans.num_channels - 1)); |
562 | 790 | ||
563 | cur_channel = triplet->chans.first_channel; | 791 | cur_channel = triplet->chans.first_channel; |
792 | |||
793 | /* | ||
794 | * Enhancement for APs that send a triplet for every channel | ||
795 | * or for whatever reason sends triplets with multiple channels | ||
796 | * separated when in fact they should be together. | ||
797 | */ | ||
798 | end_channel = max_subband_chan(band, | ||
799 | cur_channel, | ||
800 | end_channel, | ||
801 | triplet->chans.max_power, | ||
802 | &country_ie, | ||
803 | &country_ie_len); | ||
804 | if (!end_channel) | ||
805 | return NULL; | ||
806 | |||
807 | if (!chan_in_band(end_channel, band)) | ||
808 | return NULL; | ||
809 | |||
564 | cur_sub_max_channel = end_channel; | 810 | cur_sub_max_channel = end_channel; |
565 | 811 | ||
566 | /* Basic sanity check */ | 812 | /* Basic sanity check */ |
@@ -591,10 +837,13 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
591 | 837 | ||
592 | last_sub_max_channel = cur_sub_max_channel; | 838 | last_sub_max_channel = cur_sub_max_channel; |
593 | 839 | ||
594 | country_ie += 3; | ||
595 | country_ie_len -= 3; | ||
596 | num_rules++; | 840 | num_rules++; |
597 | 841 | ||
842 | if (country_ie_len >= 3) { | ||
843 | country_ie += 3; | ||
844 | country_ie_len -= 3; | ||
845 | } | ||
846 | |||
598 | /* | 847 | /* |
599 | * Note: this is not a IEEE requirement but | 848 | * Note: this is not a IEEE requirement but |
600 | * simply a memory requirement | 849 | * simply a memory requirement |
@@ -637,6 +886,12 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
637 | continue; | 886 | continue; |
638 | } | 887 | } |
639 | 888 | ||
889 | if (triplet->chans.first_channel == 0) { | ||
890 | country_ie++; | ||
891 | country_ie_len--; | ||
892 | break; | ||
893 | } | ||
894 | |||
640 | reg_rule = &rd->reg_rules[i]; | 895 | reg_rule = &rd->reg_rules[i]; |
641 | freq_range = ®_rule->freq_range; | 896 | freq_range = ®_rule->freq_range; |
642 | power_rule = ®_rule->power_rule; | 897 | power_rule = ®_rule->power_rule; |
@@ -644,13 +899,20 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
644 | reg_rule->flags = flags; | 899 | reg_rule->flags = flags; |
645 | 900 | ||
646 | /* 2 GHz */ | 901 | /* 2 GHz */ |
647 | if (triplet->chans.first_channel <= 14) | 902 | if (band == IEEE80211_BAND_2GHZ) |
648 | end_channel = triplet->chans.first_channel + | 903 | end_channel = triplet->chans.first_channel + |
649 | triplet->chans.num_channels; | 904 | triplet->chans.num_channels -1; |
650 | else | 905 | else |
651 | end_channel = triplet->chans.first_channel + | 906 | end_channel = triplet->chans.first_channel + |
652 | (4 * (triplet->chans.num_channels - 1)); | 907 | (4 * (triplet->chans.num_channels - 1)); |
653 | 908 | ||
909 | end_channel = max_subband_chan(band, | ||
910 | triplet->chans.first_channel, | ||
911 | end_channel, | ||
912 | triplet->chans.max_power, | ||
913 | &country_ie, | ||
914 | &country_ie_len); | ||
915 | |||
654 | /* | 916 | /* |
655 | * The +10 is since the regulatory domain expects | 917 | * The +10 is since the regulatory domain expects |
656 | * the actual band edge, not the center of freq for | 918 | * the actual band edge, not the center of freq for |
@@ -671,12 +933,15 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
671 | */ | 933 | */ |
672 | freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); | 934 | freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); |
673 | power_rule->max_antenna_gain = DBI_TO_MBI(100); | 935 | power_rule->max_antenna_gain = DBI_TO_MBI(100); |
674 | power_rule->max_eirp = DBM_TO_MBM(100); | 936 | power_rule->max_eirp = DBM_TO_MBM(triplet->chans.max_power); |
675 | 937 | ||
676 | country_ie += 3; | ||
677 | country_ie_len -= 3; | ||
678 | i++; | 938 | i++; |
679 | 939 | ||
940 | if (country_ie_len >= 3) { | ||
941 | country_ie += 3; | ||
942 | country_ie_len -= 3; | ||
943 | } | ||
944 | |||
680 | BUG_ON(i > NL80211_MAX_SUPP_REG_RULES); | 945 | BUG_ON(i > NL80211_MAX_SUPP_REG_RULES); |
681 | } | 946 | } |
682 | 947 | ||
@@ -972,25 +1237,21 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
972 | if (r == -ERANGE && | 1237 | if (r == -ERANGE && |
973 | last_request->initiator == | 1238 | last_request->initiator == |
974 | NL80211_REGDOM_SET_BY_COUNTRY_IE) { | 1239 | NL80211_REGDOM_SET_BY_COUNTRY_IE) { |
975 | #ifdef CONFIG_CFG80211_REG_DEBUG | 1240 | REG_DBG_PRINT("cfg80211: Leaving channel %d MHz " |
976 | printk(KERN_DEBUG "cfg80211: Leaving channel %d MHz " | ||
977 | "intact on %s - no rule found in band on " | 1241 | "intact on %s - no rule found in band on " |
978 | "Country IE\n", | 1242 | "Country IE\n", |
979 | chan->center_freq, wiphy_name(wiphy)); | 1243 | chan->center_freq, wiphy_name(wiphy)); |
980 | #endif | ||
981 | } else { | 1244 | } else { |
982 | /* | 1245 | /* |
983 | * In this case we know the country IE has at least one reg rule | 1246 | * In this case we know the country IE has at least one reg rule |
984 | * for the band so we respect its band definitions | 1247 | * for the band so we respect its band definitions |
985 | */ | 1248 | */ |
986 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
987 | if (last_request->initiator == | 1249 | if (last_request->initiator == |
988 | NL80211_REGDOM_SET_BY_COUNTRY_IE) | 1250 | NL80211_REGDOM_SET_BY_COUNTRY_IE) |
989 | printk(KERN_DEBUG "cfg80211: Disabling " | 1251 | REG_DBG_PRINT("cfg80211: Disabling " |
990 | "channel %d MHz on %s due to " | 1252 | "channel %d MHz on %s due to " |
991 | "Country IE\n", | 1253 | "Country IE\n", |
992 | chan->center_freq, wiphy_name(wiphy)); | 1254 | chan->center_freq, wiphy_name(wiphy)); |
993 | #endif | ||
994 | flags |= IEEE80211_CHAN_DISABLED; | 1255 | flags |= IEEE80211_CHAN_DISABLED; |
995 | chan->flags = flags; | 1256 | chan->flags = flags; |
996 | } | 1257 | } |
@@ -1685,7 +1946,7 @@ int regulatory_hint_user(const char *alpha2) | |||
1685 | request->wiphy_idx = WIPHY_IDX_STALE; | 1946 | request->wiphy_idx = WIPHY_IDX_STALE; |
1686 | request->alpha2[0] = alpha2[0]; | 1947 | request->alpha2[0] = alpha2[0]; |
1687 | request->alpha2[1] = alpha2[1]; | 1948 | request->alpha2[1] = alpha2[1]; |
1688 | request->initiator = NL80211_REGDOM_SET_BY_USER, | 1949 | request->initiator = NL80211_REGDOM_SET_BY_USER; |
1689 | 1950 | ||
1690 | queue_regulatory_request(request); | 1951 | queue_regulatory_request(request); |
1691 | 1952 | ||
@@ -1753,8 +2014,9 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy, | |||
1753 | * therefore cannot iterate over the rdev list here. | 2014 | * therefore cannot iterate over the rdev list here. |
1754 | */ | 2015 | */ |
1755 | void regulatory_hint_11d(struct wiphy *wiphy, | 2016 | void regulatory_hint_11d(struct wiphy *wiphy, |
1756 | u8 *country_ie, | 2017 | enum ieee80211_band band, |
1757 | u8 country_ie_len) | 2018 | u8 *country_ie, |
2019 | u8 country_ie_len) | ||
1758 | { | 2020 | { |
1759 | struct ieee80211_regdomain *rd = NULL; | 2021 | struct ieee80211_regdomain *rd = NULL; |
1760 | char alpha2[2]; | 2022 | char alpha2[2]; |
@@ -1800,9 +2062,11 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1800 | wiphy_idx_valid(last_request->wiphy_idx))) | 2062 | wiphy_idx_valid(last_request->wiphy_idx))) |
1801 | goto out; | 2063 | goto out; |
1802 | 2064 | ||
1803 | rd = country_ie_2_rd(country_ie, country_ie_len, &checksum); | 2065 | rd = country_ie_2_rd(band, country_ie, country_ie_len, &checksum); |
1804 | if (!rd) | 2066 | if (!rd) { |
2067 | REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n"); | ||
1805 | goto out; | 2068 | goto out; |
2069 | } | ||
1806 | 2070 | ||
1807 | /* | 2071 | /* |
1808 | * This will not happen right now but we leave it here for the | 2072 | * This will not happen right now but we leave it here for the |
@@ -1870,13 +2134,12 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, | |||
1870 | if (!reg_beacon) | 2134 | if (!reg_beacon) |
1871 | return -ENOMEM; | 2135 | return -ENOMEM; |
1872 | 2136 | ||
1873 | #ifdef CONFIG_CFG80211_REG_DEBUG | 2137 | REG_DBG_PRINT("cfg80211: Found new beacon on " |
1874 | printk(KERN_DEBUG "cfg80211: Found new beacon on " | 2138 | "frequency: %d MHz (Ch %d) on %s\n", |
1875 | "frequency: %d MHz (Ch %d) on %s\n", | 2139 | beacon_chan->center_freq, |
1876 | beacon_chan->center_freq, | 2140 | ieee80211_frequency_to_channel(beacon_chan->center_freq), |
1877 | ieee80211_frequency_to_channel(beacon_chan->center_freq), | 2141 | wiphy_name(wiphy)); |
1878 | wiphy_name(wiphy)); | 2142 | |
1879 | #endif | ||
1880 | memcpy(®_beacon->chan, beacon_chan, | 2143 | memcpy(®_beacon->chan, beacon_chan, |
1881 | sizeof(struct ieee80211_channel)); | 2144 | sizeof(struct ieee80211_channel)); |
1882 | 2145 | ||
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 3362c7c069b2..3018508226ab 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -41,14 +41,25 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, | |||
41 | * regulatory_hint_11d - hints a country IE as a regulatory domain | 41 | * regulatory_hint_11d - hints a country IE as a regulatory domain |
42 | * @wiphy: the wireless device giving the hint (used only for reporting | 42 | * @wiphy: the wireless device giving the hint (used only for reporting |
43 | * conflicts) | 43 | * conflicts) |
44 | * @band: the band on which the country IE was received on. This determines | ||
45 | * the band we'll process the country IE channel triplets for. | ||
44 | * @country_ie: pointer to the country IE | 46 | * @country_ie: pointer to the country IE |
45 | * @country_ie_len: length of the country IE | 47 | * @country_ie_len: length of the country IE |
46 | * | 48 | * |
47 | * We will intersect the rd with the what CRDA tells us should apply | 49 | * We will intersect the rd with the what CRDA tells us should apply |
48 | * for the alpha2 this country IE belongs to, this prevents APs from | 50 | * for the alpha2 this country IE belongs to, this prevents APs from |
49 | * sending us incorrect or outdated information against a country. | 51 | * sending us incorrect or outdated information against a country. |
52 | * | ||
53 | * The AP is expected to provide Country IE channel triplets for the | ||
54 | * band it is on. It is technically possible for APs to send channel | ||
55 | * country IE triplets even for channels outside of the band they are | ||
56 | * in but for that they would have to use the regulatory extension | ||
57 | * in combination with a triplet but this behaviour is currently | ||
58 | * not observed. For this reason if a triplet is seen with channel | ||
59 | * information for a band the BSS is not present in it will be ignored. | ||
50 | */ | 60 | */ |
51 | void regulatory_hint_11d(struct wiphy *wiphy, | 61 | void regulatory_hint_11d(struct wiphy *wiphy, |
62 | enum ieee80211_band band, | ||
52 | u8 *country_ie, | 63 | u8 *country_ie, |
53 | u8 country_ie_len); | 64 | u8 country_ie_len); |
54 | 65 | ||
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0c2cbbebca95..06b0231ee5e3 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -100,8 +100,10 @@ static void bss_release(struct kref *ref) | |||
100 | if (bss->pub.free_priv) | 100 | if (bss->pub.free_priv) |
101 | bss->pub.free_priv(&bss->pub); | 101 | bss->pub.free_priv(&bss->pub); |
102 | 102 | ||
103 | if (bss->ies_allocated) | 103 | if (bss->beacon_ies_allocated) |
104 | kfree(bss->pub.information_elements); | 104 | kfree(bss->pub.beacon_ies); |
105 | if (bss->proberesp_ies_allocated) | ||
106 | kfree(bss->pub.proberesp_ies); | ||
105 | 107 | ||
106 | BUG_ON(atomic_read(&bss->hold)); | 108 | BUG_ON(atomic_read(&bss->hold)); |
107 | 109 | ||
@@ -375,8 +377,7 @@ rb_find_bss(struct cfg80211_registered_device *dev, | |||
375 | 377 | ||
376 | static struct cfg80211_internal_bss * | 378 | static struct cfg80211_internal_bss * |
377 | cfg80211_bss_update(struct cfg80211_registered_device *dev, | 379 | cfg80211_bss_update(struct cfg80211_registered_device *dev, |
378 | struct cfg80211_internal_bss *res, | 380 | struct cfg80211_internal_bss *res) |
379 | bool overwrite) | ||
380 | { | 381 | { |
381 | struct cfg80211_internal_bss *found = NULL; | 382 | struct cfg80211_internal_bss *found = NULL; |
382 | const u8 *meshid, *meshcfg; | 383 | const u8 *meshid, *meshcfg; |
@@ -418,28 +419,64 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
418 | found->pub.capability = res->pub.capability; | 419 | found->pub.capability = res->pub.capability; |
419 | found->ts = res->ts; | 420 | found->ts = res->ts; |
420 | 421 | ||
421 | /* overwrite IEs */ | 422 | /* Update IEs */ |
422 | if (overwrite) { | 423 | if (res->pub.proberesp_ies) { |
423 | size_t used = dev->wiphy.bss_priv_size + sizeof(*res); | 424 | size_t used = dev->wiphy.bss_priv_size + sizeof(*res); |
424 | size_t ielen = res->pub.len_information_elements; | 425 | size_t ielen = res->pub.len_proberesp_ies; |
426 | |||
427 | if (found->pub.proberesp_ies && | ||
428 | !found->proberesp_ies_allocated && | ||
429 | ksize(found) >= used + ielen) { | ||
430 | memcpy(found->pub.proberesp_ies, | ||
431 | res->pub.proberesp_ies, ielen); | ||
432 | found->pub.len_proberesp_ies = ielen; | ||
433 | } else { | ||
434 | u8 *ies = found->pub.proberesp_ies; | ||
435 | |||
436 | if (found->proberesp_ies_allocated) | ||
437 | ies = krealloc(ies, ielen, GFP_ATOMIC); | ||
438 | else | ||
439 | ies = kmalloc(ielen, GFP_ATOMIC); | ||
440 | |||
441 | if (ies) { | ||
442 | memcpy(ies, res->pub.proberesp_ies, | ||
443 | ielen); | ||
444 | found->proberesp_ies_allocated = true; | ||
445 | found->pub.proberesp_ies = ies; | ||
446 | found->pub.len_proberesp_ies = ielen; | ||
447 | } | ||
448 | } | ||
425 | 449 | ||
426 | if (!found->ies_allocated && ksize(found) >= used + ielen) { | 450 | /* Override possible earlier Beacon frame IEs */ |
427 | memcpy(found->pub.information_elements, | 451 | found->pub.information_elements = |
428 | res->pub.information_elements, ielen); | 452 | found->pub.proberesp_ies; |
429 | found->pub.len_information_elements = ielen; | 453 | found->pub.len_information_elements = |
454 | found->pub.len_proberesp_ies; | ||
455 | } | ||
456 | if (res->pub.beacon_ies) { | ||
457 | size_t used = dev->wiphy.bss_priv_size + sizeof(*res); | ||
458 | size_t ielen = res->pub.len_beacon_ies; | ||
459 | |||
460 | if (found->pub.beacon_ies && | ||
461 | !found->beacon_ies_allocated && | ||
462 | ksize(found) >= used + ielen) { | ||
463 | memcpy(found->pub.beacon_ies, | ||
464 | res->pub.beacon_ies, ielen); | ||
465 | found->pub.len_beacon_ies = ielen; | ||
430 | } else { | 466 | } else { |
431 | u8 *ies = found->pub.information_elements; | 467 | u8 *ies = found->pub.beacon_ies; |
432 | 468 | ||
433 | if (found->ies_allocated) | 469 | if (found->beacon_ies_allocated) |
434 | ies = krealloc(ies, ielen, GFP_ATOMIC); | 470 | ies = krealloc(ies, ielen, GFP_ATOMIC); |
435 | else | 471 | else |
436 | ies = kmalloc(ielen, GFP_ATOMIC); | 472 | ies = kmalloc(ielen, GFP_ATOMIC); |
437 | 473 | ||
438 | if (ies) { | 474 | if (ies) { |
439 | memcpy(ies, res->pub.information_elements, ielen); | 475 | memcpy(ies, res->pub.beacon_ies, |
440 | found->ies_allocated = true; | 476 | ielen); |
441 | found->pub.information_elements = ies; | 477 | found->beacon_ies_allocated = true; |
442 | found->pub.len_information_elements = ielen; | 478 | found->pub.beacon_ies = ies; |
479 | found->pub.len_beacon_ies = ielen; | ||
443 | } | 480 | } |
444 | } | 481 | } |
445 | } | 482 | } |
@@ -489,14 +526,26 @@ cfg80211_inform_bss(struct wiphy *wiphy, | |||
489 | res->pub.tsf = timestamp; | 526 | res->pub.tsf = timestamp; |
490 | res->pub.beacon_interval = beacon_interval; | 527 | res->pub.beacon_interval = beacon_interval; |
491 | res->pub.capability = capability; | 528 | res->pub.capability = capability; |
492 | /* point to after the private area */ | 529 | /* |
493 | res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz; | 530 | * Since we do not know here whether the IEs are from a Beacon or Probe |
494 | memcpy(res->pub.information_elements, ie, ielen); | 531 | * Response frame, we need to pick one of the options and only use it |
495 | res->pub.len_information_elements = ielen; | 532 | * with the driver that does not provide the full Beacon/Probe Response |
533 | * frame. Use Beacon frame pointer to avoid indicating that this should | ||
534 | * override the information_elements pointer should we have received an | ||
535 | * earlier indication of Probe Response data. | ||
536 | * | ||
537 | * The initial buffer for the IEs is allocated with the BSS entry and | ||
538 | * is located after the private area. | ||
539 | */ | ||
540 | res->pub.beacon_ies = (u8 *)res + sizeof(*res) + privsz; | ||
541 | memcpy(res->pub.beacon_ies, ie, ielen); | ||
542 | res->pub.len_beacon_ies = ielen; | ||
543 | res->pub.information_elements = res->pub.beacon_ies; | ||
544 | res->pub.len_information_elements = res->pub.len_beacon_ies; | ||
496 | 545 | ||
497 | kref_init(&res->ref); | 546 | kref_init(&res->ref); |
498 | 547 | ||
499 | res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, 0); | 548 | res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); |
500 | if (!res) | 549 | if (!res) |
501 | return NULL; | 550 | return NULL; |
502 | 551 | ||
@@ -517,7 +566,6 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
517 | struct cfg80211_internal_bss *res; | 566 | struct cfg80211_internal_bss *res; |
518 | size_t ielen = len - offsetof(struct ieee80211_mgmt, | 567 | size_t ielen = len - offsetof(struct ieee80211_mgmt, |
519 | u.probe_resp.variable); | 568 | u.probe_resp.variable); |
520 | bool overwrite; | ||
521 | size_t privsz = wiphy->bss_priv_size; | 569 | size_t privsz = wiphy->bss_priv_size; |
522 | 570 | ||
523 | if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC && | 571 | if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC && |
@@ -538,16 +586,28 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
538 | res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); | 586 | res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); |
539 | res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); | 587 | res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); |
540 | res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); | 588 | res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); |
541 | /* point to after the private area */ | 589 | /* |
542 | res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz; | 590 | * The initial buffer for the IEs is allocated with the BSS entry and |
543 | memcpy(res->pub.information_elements, mgmt->u.probe_resp.variable, ielen); | 591 | * is located after the private area. |
544 | res->pub.len_information_elements = ielen; | 592 | */ |
593 | if (ieee80211_is_probe_resp(mgmt->frame_control)) { | ||
594 | res->pub.proberesp_ies = (u8 *) res + sizeof(*res) + privsz; | ||
595 | memcpy(res->pub.proberesp_ies, mgmt->u.probe_resp.variable, | ||
596 | ielen); | ||
597 | res->pub.len_proberesp_ies = ielen; | ||
598 | res->pub.information_elements = res->pub.proberesp_ies; | ||
599 | res->pub.len_information_elements = res->pub.len_proberesp_ies; | ||
600 | } else { | ||
601 | res->pub.beacon_ies = (u8 *) res + sizeof(*res) + privsz; | ||
602 | memcpy(res->pub.beacon_ies, mgmt->u.beacon.variable, ielen); | ||
603 | res->pub.len_beacon_ies = ielen; | ||
604 | res->pub.information_elements = res->pub.beacon_ies; | ||
605 | res->pub.len_information_elements = res->pub.len_beacon_ies; | ||
606 | } | ||
545 | 607 | ||
546 | kref_init(&res->ref); | 608 | kref_init(&res->ref); |
547 | 609 | ||
548 | overwrite = ieee80211_is_probe_resp(mgmt->frame_control); | 610 | res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); |
549 | |||
550 | res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, overwrite); | ||
551 | if (!res) | 611 | if (!res) |
552 | return NULL; | 612 | return NULL; |
553 | 613 | ||
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 2333d78187e4..2ce5e1609a3d 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -454,6 +454,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
454 | * - and country_ie[1] which is the IE length | 454 | * - and country_ie[1] which is the IE length |
455 | */ | 455 | */ |
456 | regulatory_hint_11d(wdev->wiphy, | 456 | regulatory_hint_11d(wdev->wiphy, |
457 | bss->channel->band, | ||
457 | country_ie + 2, | 458 | country_ie + 2, |
458 | country_ie[1]); | 459 | country_ie[1]); |
459 | } | 460 | } |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 4198243a3dff..966d2f01beac 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -1204,21 +1204,47 @@ int cfg80211_wext_siwrate(struct net_device *dev, | |||
1204 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1204 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1205 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 1205 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1206 | struct cfg80211_bitrate_mask mask; | 1206 | struct cfg80211_bitrate_mask mask; |
1207 | u32 fixed, maxrate; | ||
1208 | struct ieee80211_supported_band *sband; | ||
1209 | int band, ridx; | ||
1210 | bool match = false; | ||
1207 | 1211 | ||
1208 | if (!rdev->ops->set_bitrate_mask) | 1212 | if (!rdev->ops->set_bitrate_mask) |
1209 | return -EOPNOTSUPP; | 1213 | return -EOPNOTSUPP; |
1210 | 1214 | ||
1211 | mask.fixed = 0; | 1215 | memset(&mask, 0, sizeof(mask)); |
1212 | mask.maxrate = 0; | 1216 | fixed = 0; |
1217 | maxrate = 0; | ||
1213 | 1218 | ||
1214 | if (rate->value < 0) { | 1219 | if (rate->value < 0) { |
1215 | /* nothing */ | 1220 | /* nothing */ |
1216 | } else if (rate->fixed) { | 1221 | } else if (rate->fixed) { |
1217 | mask.fixed = rate->value / 1000; /* kbps */ | 1222 | fixed = rate->value / 100000; |
1218 | } else { | 1223 | } else { |
1219 | mask.maxrate = rate->value / 1000; /* kbps */ | 1224 | maxrate = rate->value / 100000; |
1225 | } | ||
1226 | |||
1227 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
1228 | sband = wdev->wiphy->bands[band]; | ||
1229 | if (sband == NULL) | ||
1230 | continue; | ||
1231 | for (ridx = 0; ridx < sband->n_bitrates; ridx++) { | ||
1232 | struct ieee80211_rate *srate = &sband->bitrates[ridx]; | ||
1233 | if (fixed == srate->bitrate) { | ||
1234 | mask.control[band].legacy = 1 << ridx; | ||
1235 | match = true; | ||
1236 | break; | ||
1237 | } | ||
1238 | if (srate->bitrate <= maxrate) { | ||
1239 | mask.control[band].legacy |= 1 << ridx; | ||
1240 | match = true; | ||
1241 | } | ||
1242 | } | ||
1220 | } | 1243 | } |
1221 | 1244 | ||
1245 | if (!match) | ||
1246 | return -EINVAL; | ||
1247 | |||
1222 | return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); | 1248 | return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); |
1223 | } | 1249 | } |
1224 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate); | 1250 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate); |