diff options
author | David S. Miller <davem@davemloft.net> | 2011-07-22 20:01:44 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-07-22 20:01:44 -0400 |
commit | f9035cd498486d5a82ad8ae9bcfdb91b3e57ec9d (patch) | |
tree | f90d0fc8abc1edf7fd161252704bb5675f3460d0 /net | |
parent | 1821f7cd65ad9ea56580b830ac79bf4c4fef59cb (diff) | |
parent | 41bf37117b47fc5ce2aae91f6a108e7e42e0b046 (diff) |
Merge branch 'for-davem' of ssh://master.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/agg-rx.c | 10 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 4 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 31 | ||||
-rw-r--r-- | net/mac80211/driver-trace.h | 43 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 7 | ||||
-rw-r--r-- | net/mac80211/key.c | 2 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 30 | ||||
-rw-r--r-- | net/mac80211/pm.c | 3 | ||||
-rw-r--r-- | net/mac80211/scan.c | 6 | ||||
-rw-r--r-- | net/mac80211/tkip.c | 11 | ||||
-rw-r--r-- | net/mac80211/util.c | 71 | ||||
-rw-r--r-- | net/mac80211/work.c | 28 | ||||
-rw-r--r-- | net/wireless/core.c | 7 | ||||
-rw-r--r-- | net/wireless/core.h | 4 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 109 | ||||
-rw-r--r-- | net/wireless/scan.c | 4 | ||||
-rw-r--r-- | net/wireless/util.c | 38 |
17 files changed, 340 insertions, 68 deletions
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index ebadb9ac9a7e..fd1aaf2a4a6c 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -104,14 +104,22 @@ void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap, | |||
104 | const u8 *addr) | 104 | const u8 *addr) |
105 | { | 105 | { |
106 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 106 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
107 | struct sta_info *sta = sta_info_get(sdata, addr); | 107 | struct sta_info *sta; |
108 | int i; | 108 | int i; |
109 | 109 | ||
110 | rcu_read_lock(); | ||
111 | sta = sta_info_get(sdata, addr); | ||
112 | if (!sta) { | ||
113 | rcu_read_unlock(); | ||
114 | return; | ||
115 | } | ||
116 | |||
110 | for (i = 0; i < STA_TID_NUM; i++) | 117 | for (i = 0; i < STA_TID_NUM; i++) |
111 | if (ba_rx_bitmap & BIT(i)) | 118 | if (ba_rx_bitmap & BIT(i)) |
112 | set_bit(i, sta->ampdu_mlme.tid_rx_stop_requested); | 119 | set_bit(i, sta->ampdu_mlme.tid_rx_stop_requested); |
113 | 120 | ||
114 | ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work); | 121 | ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work); |
122 | rcu_read_unlock(); | ||
115 | } | 123 | } |
116 | EXPORT_SYMBOL(ieee80211_stop_rx_ba_session); | 124 | EXPORT_SYMBOL(ieee80211_stop_rx_ba_session); |
117 | 125 | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index bfc36e904764..3d1b091d9b2e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1255,6 +1255,10 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, | |||
1255 | */ | 1255 | */ |
1256 | p.uapsd = false; | 1256 | p.uapsd = false; |
1257 | 1257 | ||
1258 | if (params->queue >= local->hw.queues) | ||
1259 | return -EINVAL; | ||
1260 | |||
1261 | local->tx_conf[params->queue] = p; | ||
1258 | if (drv_conf_tx(local, params->queue, &p)) { | 1262 | if (drv_conf_tx(local, params->queue, &p)) { |
1259 | wiphy_debug(local->hw.wiphy, | 1263 | wiphy_debug(local->hw.wiphy, |
1260 | "failed to set TX queue parameters for queue %d\n", | 1264 | "failed to set TX queue parameters for queue %d\n", |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index b2d6bba44054..1425380983f7 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -130,6 +130,37 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, | |||
130 | trace_drv_return_void(local); | 130 | trace_drv_return_void(local); |
131 | } | 131 | } |
132 | 132 | ||
133 | static inline int drv_tx_sync(struct ieee80211_local *local, | ||
134 | struct ieee80211_sub_if_data *sdata, | ||
135 | const u8 *bssid, | ||
136 | enum ieee80211_tx_sync_type type) | ||
137 | { | ||
138 | int ret = 0; | ||
139 | |||
140 | might_sleep(); | ||
141 | |||
142 | trace_drv_tx_sync(local, sdata, bssid, type); | ||
143 | if (local->ops->tx_sync) | ||
144 | ret = local->ops->tx_sync(&local->hw, &sdata->vif, | ||
145 | bssid, type); | ||
146 | trace_drv_return_int(local, ret); | ||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | static inline void drv_finish_tx_sync(struct ieee80211_local *local, | ||
151 | struct ieee80211_sub_if_data *sdata, | ||
152 | const u8 *bssid, | ||
153 | enum ieee80211_tx_sync_type type) | ||
154 | { | ||
155 | might_sleep(); | ||
156 | |||
157 | trace_drv_finish_tx_sync(local, sdata, bssid, type); | ||
158 | if (local->ops->finish_tx_sync) | ||
159 | local->ops->finish_tx_sync(&local->hw, &sdata->vif, | ||
160 | bssid, type); | ||
161 | trace_drv_return_void(local); | ||
162 | } | ||
163 | |||
133 | static inline u64 drv_prepare_multicast(struct ieee80211_local *local, | 164 | static inline u64 drv_prepare_multicast(struct ieee80211_local *local, |
134 | struct netdev_hw_addr_list *mc_list) | 165 | struct netdev_hw_addr_list *mc_list) |
135 | { | 166 | { |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 4470f6e8b845..f47b00dc7afd 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -319,6 +319,49 @@ TRACE_EVENT(drv_bss_info_changed, | |||
319 | ) | 319 | ) |
320 | ); | 320 | ); |
321 | 321 | ||
322 | DECLARE_EVENT_CLASS(tx_sync_evt, | ||
323 | TP_PROTO(struct ieee80211_local *local, | ||
324 | struct ieee80211_sub_if_data *sdata, | ||
325 | const u8 *bssid, | ||
326 | enum ieee80211_tx_sync_type type), | ||
327 | TP_ARGS(local, sdata, bssid, type), | ||
328 | |||
329 | TP_STRUCT__entry( | ||
330 | LOCAL_ENTRY | ||
331 | VIF_ENTRY | ||
332 | __array(char, bssid, ETH_ALEN) | ||
333 | __field(u32, sync_type) | ||
334 | ), | ||
335 | |||
336 | TP_fast_assign( | ||
337 | LOCAL_ASSIGN; | ||
338 | VIF_ASSIGN; | ||
339 | memcpy(__entry->bssid, bssid, ETH_ALEN); | ||
340 | __entry->sync_type = type; | ||
341 | ), | ||
342 | |||
343 | TP_printk( | ||
344 | LOCAL_PR_FMT VIF_PR_FMT " bssid:%pM type:%d", | ||
345 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->bssid, __entry->sync_type | ||
346 | ) | ||
347 | ); | ||
348 | |||
349 | DEFINE_EVENT(tx_sync_evt, drv_tx_sync, | ||
350 | TP_PROTO(struct ieee80211_local *local, | ||
351 | struct ieee80211_sub_if_data *sdata, | ||
352 | const u8 *bssid, | ||
353 | enum ieee80211_tx_sync_type type), | ||
354 | TP_ARGS(local, sdata, bssid, type) | ||
355 | ); | ||
356 | |||
357 | DEFINE_EVENT(tx_sync_evt, drv_finish_tx_sync, | ||
358 | TP_PROTO(struct ieee80211_local *local, | ||
359 | struct ieee80211_sub_if_data *sdata, | ||
360 | const u8 *bssid, | ||
361 | enum ieee80211_tx_sync_type type), | ||
362 | TP_ARGS(local, sdata, bssid, type) | ||
363 | ); | ||
364 | |||
322 | TRACE_EVENT(drv_prepare_multicast, | 365 | TRACE_EVENT(drv_prepare_multicast, |
323 | TP_PROTO(struct ieee80211_local *local, int mc_count), | 366 | TP_PROTO(struct ieee80211_local *local, int mc_count), |
324 | 367 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index dda0d1ab34f3..400c09bea639 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -323,6 +323,7 @@ struct ieee80211_work { | |||
323 | u8 key[WLAN_KEY_LEN_WEP104]; | 323 | u8 key[WLAN_KEY_LEN_WEP104]; |
324 | u8 key_len, key_idx; | 324 | u8 key_len, key_idx; |
325 | bool privacy; | 325 | bool privacy; |
326 | bool synced; | ||
326 | } probe_auth; | 327 | } probe_auth; |
327 | struct { | 328 | struct { |
328 | struct cfg80211_bss *bss; | 329 | struct cfg80211_bss *bss; |
@@ -336,6 +337,7 @@ struct ieee80211_work { | |||
336 | u8 ssid_len; | 337 | u8 ssid_len; |
337 | u8 supp_rates_len; | 338 | u8 supp_rates_len; |
338 | bool wmm_used, use_11n, uapsd_used; | 339 | bool wmm_used, use_11n, uapsd_used; |
340 | bool synced; | ||
339 | } assoc; | 341 | } assoc; |
340 | struct { | 342 | struct { |
341 | u32 duration; | 343 | u32 duration; |
@@ -746,6 +748,7 @@ struct ieee80211_local { | |||
746 | struct workqueue_struct *workqueue; | 748 | struct workqueue_struct *workqueue; |
747 | 749 | ||
748 | unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES]; | 750 | unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES]; |
751 | struct ieee80211_tx_queue_params tx_conf[IEEE80211_MAX_QUEUES]; | ||
749 | /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ | 752 | /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ |
750 | spinlock_t queue_stop_reason_lock; | 753 | spinlock_t queue_stop_reason_lock; |
751 | 754 | ||
@@ -1376,14 +1379,14 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1376 | enum ieee80211_band band, u32 rate_mask, | 1379 | enum ieee80211_band band, u32 rate_mask, |
1377 | u8 channel); | 1380 | u8 channel); |
1378 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1381 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
1379 | u8 *dst, | 1382 | u8 *dst, u32 ratemask, |
1380 | const u8 *ssid, size_t ssid_len, | 1383 | const u8 *ssid, size_t ssid_len, |
1381 | const u8 *ie, size_t ie_len, | 1384 | const u8 *ie, size_t ie_len, |
1382 | bool directed); | 1385 | bool directed); |
1383 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 1386 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
1384 | const u8 *ssid, size_t ssid_len, | 1387 | const u8 *ssid, size_t ssid_len, |
1385 | const u8 *ie, size_t ie_len, | 1388 | const u8 *ie, size_t ie_len, |
1386 | bool directed); | 1389 | u32 ratemask, bool directed); |
1387 | 1390 | ||
1388 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | 1391 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, |
1389 | const size_t supp_rates_len, | 1392 | const size_t supp_rates_len, |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 739bee13e813..5150c6d11b57 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -278,7 +278,7 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
278 | bool defunikey, defmultikey, defmgmtkey; | 278 | bool defunikey, defmultikey, defmgmtkey; |
279 | 279 | ||
280 | if (new) | 280 | if (new) |
281 | list_add(&new->list, &sdata->key_list); | 281 | list_add_tail(&new->list, &sdata->key_list); |
282 | 282 | ||
283 | if (sta && pairwise) { | 283 | if (sta && pairwise) { |
284 | rcu_assign_pointer(sta->ptk, new); | 284 | rcu_assign_pointer(sta->ptk, new); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c99237cd4b98..d6470c7fd6ce 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -917,6 +917,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
917 | params.aifs, params.cw_min, params.cw_max, | 917 | params.aifs, params.cw_min, params.cw_max, |
918 | params.txop, params.uapsd); | 918 | params.txop, params.uapsd); |
919 | #endif | 919 | #endif |
920 | local->tx_conf[queue] = params; | ||
920 | if (drv_conf_tx(local, queue, ¶ms)) | 921 | if (drv_conf_tx(local, queue, ¶ms)) |
921 | wiphy_debug(local->hw.wiphy, | 922 | wiphy_debug(local->hw.wiphy, |
922 | "failed to set TX queue parameters for queue %d\n", | 923 | "failed to set TX queue parameters for queue %d\n", |
@@ -1219,7 +1220,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
1219 | } else { | 1220 | } else { |
1220 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | 1221 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); |
1221 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0, | 1222 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0, |
1222 | true); | 1223 | (u32) -1, true); |
1223 | } | 1224 | } |
1224 | 1225 | ||
1225 | ifmgd->probe_send_count++; | 1226 | ifmgd->probe_send_count++; |
@@ -1304,7 +1305,8 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
1304 | 1305 | ||
1305 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | 1306 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); |
1306 | skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, | 1307 | skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, |
1307 | ssid + 2, ssid[1], NULL, 0, true); | 1308 | (u32) -1, ssid + 2, ssid[1], |
1309 | NULL, 0, true); | ||
1308 | 1310 | ||
1309 | return skb; | 1311 | return skb; |
1310 | } | 1312 | } |
@@ -2333,14 +2335,16 @@ static enum work_done_result | |||
2333 | ieee80211_probe_auth_done(struct ieee80211_work *wk, | 2335 | ieee80211_probe_auth_done(struct ieee80211_work *wk, |
2334 | struct sk_buff *skb) | 2336 | struct sk_buff *skb) |
2335 | { | 2337 | { |
2338 | struct ieee80211_local *local = wk->sdata->local; | ||
2339 | |||
2336 | if (!skb) { | 2340 | if (!skb) { |
2337 | cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta); | 2341 | cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta); |
2338 | return WORK_DONE_DESTROY; | 2342 | goto destroy; |
2339 | } | 2343 | } |
2340 | 2344 | ||
2341 | if (wk->type == IEEE80211_WORK_AUTH) { | 2345 | if (wk->type == IEEE80211_WORK_AUTH) { |
2342 | cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len); | 2346 | cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len); |
2343 | return WORK_DONE_DESTROY; | 2347 | goto destroy; |
2344 | } | 2348 | } |
2345 | 2349 | ||
2346 | mutex_lock(&wk->sdata->u.mgd.mtx); | 2350 | mutex_lock(&wk->sdata->u.mgd.mtx); |
@@ -2350,6 +2354,12 @@ ieee80211_probe_auth_done(struct ieee80211_work *wk, | |||
2350 | wk->type = IEEE80211_WORK_AUTH; | 2354 | wk->type = IEEE80211_WORK_AUTH; |
2351 | wk->probe_auth.tries = 0; | 2355 | wk->probe_auth.tries = 0; |
2352 | return WORK_DONE_REQUEUE; | 2356 | return WORK_DONE_REQUEUE; |
2357 | destroy: | ||
2358 | if (wk->probe_auth.synced) | ||
2359 | drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, | ||
2360 | IEEE80211_TX_SYNC_AUTH); | ||
2361 | |||
2362 | return WORK_DONE_DESTROY; | ||
2353 | } | 2363 | } |
2354 | 2364 | ||
2355 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | 2365 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, |
@@ -2422,6 +2432,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
2422 | static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | 2432 | static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, |
2423 | struct sk_buff *skb) | 2433 | struct sk_buff *skb) |
2424 | { | 2434 | { |
2435 | struct ieee80211_local *local = wk->sdata->local; | ||
2425 | struct ieee80211_mgmt *mgmt; | 2436 | struct ieee80211_mgmt *mgmt; |
2426 | struct ieee80211_rx_status *rx_status; | 2437 | struct ieee80211_rx_status *rx_status; |
2427 | struct ieee802_11_elems elems; | 2438 | struct ieee802_11_elems elems; |
@@ -2429,7 +2440,7 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | |||
2429 | 2440 | ||
2430 | if (!skb) { | 2441 | if (!skb) { |
2431 | cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); | 2442 | cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); |
2432 | return WORK_DONE_DESTROY; | 2443 | goto destroy; |
2433 | } | 2444 | } |
2434 | 2445 | ||
2435 | if (wk->type == IEEE80211_WORK_ASSOC_BEACON_WAIT) { | 2446 | if (wk->type == IEEE80211_WORK_ASSOC_BEACON_WAIT) { |
@@ -2449,6 +2460,10 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | |||
2449 | status = le16_to_cpu(mgmt->u.assoc_resp.status_code); | 2460 | status = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
2450 | 2461 | ||
2451 | if (status == WLAN_STATUS_SUCCESS) { | 2462 | if (status == WLAN_STATUS_SUCCESS) { |
2463 | if (wk->assoc.synced) | ||
2464 | drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, | ||
2465 | IEEE80211_TX_SYNC_ASSOC); | ||
2466 | |||
2452 | mutex_lock(&wk->sdata->u.mgd.mtx); | 2467 | mutex_lock(&wk->sdata->u.mgd.mtx); |
2453 | if (!ieee80211_assoc_success(wk, mgmt, skb->len)) { | 2468 | if (!ieee80211_assoc_success(wk, mgmt, skb->len)) { |
2454 | mutex_unlock(&wk->sdata->u.mgd.mtx); | 2469 | mutex_unlock(&wk->sdata->u.mgd.mtx); |
@@ -2462,6 +2477,11 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | |||
2462 | } | 2477 | } |
2463 | 2478 | ||
2464 | cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); | 2479 | cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); |
2480 | destroy: | ||
2481 | if (wk->assoc.synced) | ||
2482 | drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, | ||
2483 | IEEE80211_TX_SYNC_ASSOC); | ||
2484 | |||
2465 | return WORK_DONE_DESTROY; | 2485 | return WORK_DONE_DESTROY; |
2466 | } | 2486 | } |
2467 | 2487 | ||
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index f87e993e713b..6326d3439861 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -34,6 +34,9 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
34 | struct ieee80211_sub_if_data *sdata; | 34 | struct ieee80211_sub_if_data *sdata; |
35 | struct sta_info *sta; | 35 | struct sta_info *sta; |
36 | 36 | ||
37 | if (!local->open_count) | ||
38 | goto suspend; | ||
39 | |||
37 | ieee80211_scan_cancel(local); | 40 | ieee80211_scan_cancel(local); |
38 | 41 | ||
39 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | 42 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 08a45ac3d6f8..6f09eca01112 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -228,7 +228,6 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
228 | static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | 228 | static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) |
229 | { | 229 | { |
230 | struct cfg80211_scan_request *req = local->scan_req; | 230 | struct cfg80211_scan_request *req = local->scan_req; |
231 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | ||
232 | enum ieee80211_band band; | 231 | enum ieee80211_band band; |
233 | int i, ielen, n_chans; | 232 | int i, ielen, n_chans; |
234 | 233 | ||
@@ -253,7 +252,7 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | |||
253 | 252 | ||
254 | ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, | 253 | ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, |
255 | req->ie, req->ie_len, band, | 254 | req->ie, req->ie_len, band, |
256 | sdata->rc_rateidx_mask[band], 0); | 255 | req->rates[band], 0); |
257 | local->hw_scan_req->ie_len = ielen; | 256 | local->hw_scan_req->ie_len = ielen; |
258 | 257 | ||
259 | return true; | 258 | return true; |
@@ -653,6 +652,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, | |||
653 | { | 652 | { |
654 | int i; | 653 | int i; |
655 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | 654 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; |
655 | enum ieee80211_band band = local->hw.conf.channel->band; | ||
656 | 656 | ||
657 | for (i = 0; i < local->scan_req->n_ssids; i++) | 657 | for (i = 0; i < local->scan_req->n_ssids; i++) |
658 | ieee80211_send_probe_req( | 658 | ieee80211_send_probe_req( |
@@ -660,7 +660,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, | |||
660 | local->scan_req->ssids[i].ssid, | 660 | local->scan_req->ssids[i].ssid, |
661 | local->scan_req->ssids[i].ssid_len, | 661 | local->scan_req->ssids[i].ssid_len, |
662 | local->scan_req->ie, local->scan_req->ie_len, | 662 | local->scan_req->ie, local->scan_req->ie_len, |
663 | false); | 663 | local->scan_req->rates[band], false); |
664 | 664 | ||
665 | /* | 665 | /* |
666 | * After sending probe requests, wait for probe responses | 666 | * After sending probe requests, wait for probe responses |
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index cc79e697cdb2..f49d00a4c7fd 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c | |||
@@ -185,6 +185,17 @@ void ieee80211_get_tkip_p1k_iv(struct ieee80211_key_conf *keyconf, | |||
185 | } | 185 | } |
186 | EXPORT_SYMBOL(ieee80211_get_tkip_p1k_iv); | 186 | EXPORT_SYMBOL(ieee80211_get_tkip_p1k_iv); |
187 | 187 | ||
188 | void ieee80211_get_tkip_rx_p1k(struct ieee80211_key_conf *keyconf, | ||
189 | const u8 *ta, u32 iv32, u16 *p1k) | ||
190 | { | ||
191 | const u8 *tk = &keyconf->key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; | ||
192 | struct tkip_ctx ctx; | ||
193 | |||
194 | tkip_mixing_phase1(tk, &ctx, ta, iv32); | ||
195 | memcpy(p1k, ctx.p1k, sizeof(ctx.p1k)); | ||
196 | } | ||
197 | EXPORT_SYMBOL(ieee80211_get_tkip_rx_p1k); | ||
198 | |||
188 | void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf, | 199 | void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf, |
189 | struct sk_buff *skb, u8 *p2k) | 200 | struct sk_buff *skb, u8 *p2k) |
190 | { | 201 | { |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5bfb80cba634..ddeb1b998383 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -799,6 +799,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) | |||
799 | 799 | ||
800 | qparam.uapsd = false; | 800 | qparam.uapsd = false; |
801 | 801 | ||
802 | local->tx_conf[queue] = qparam; | ||
802 | drv_conf_tx(local, queue, &qparam); | 803 | drv_conf_tx(local, queue, &qparam); |
803 | } | 804 | } |
804 | 805 | ||
@@ -1016,7 +1017,7 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1016 | } | 1017 | } |
1017 | 1018 | ||
1018 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1019 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
1019 | u8 *dst, | 1020 | u8 *dst, u32 ratemask, |
1020 | const u8 *ssid, size_t ssid_len, | 1021 | const u8 *ssid, size_t ssid_len, |
1021 | const u8 *ie, size_t ie_len, | 1022 | const u8 *ie, size_t ie_len, |
1022 | bool directed) | 1023 | bool directed) |
@@ -1049,9 +1050,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1049 | 1050 | ||
1050 | buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, | 1051 | buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, |
1051 | local->hw.conf.channel->band, | 1052 | local->hw.conf.channel->band, |
1052 | sdata->rc_rateidx_mask | 1053 | ratemask, chan); |
1053 | [local->hw.conf.channel->band], | ||
1054 | chan); | ||
1055 | 1054 | ||
1056 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, | 1055 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, |
1057 | ssid, ssid_len, | 1056 | ssid, ssid_len, |
@@ -1072,12 +1071,12 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1072 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 1071 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
1073 | const u8 *ssid, size_t ssid_len, | 1072 | const u8 *ssid, size_t ssid_len, |
1074 | const u8 *ie, size_t ie_len, | 1073 | const u8 *ie, size_t ie_len, |
1075 | bool directed) | 1074 | u32 ratemask, bool directed) |
1076 | { | 1075 | { |
1077 | struct sk_buff *skb; | 1076 | struct sk_buff *skb; |
1078 | 1077 | ||
1079 | skb = ieee80211_build_probe_req(sdata, dst, ssid, ssid_len, ie, ie_len, | 1078 | skb = ieee80211_build_probe_req(sdata, dst, ratemask, ssid, ssid_len, |
1080 | directed); | 1079 | ie, ie_len, directed); |
1081 | if (skb) | 1080 | if (skb) |
1082 | ieee80211_tx_skb(sdata, skb); | 1081 | ieee80211_tx_skb(sdata, skb); |
1083 | } | 1082 | } |
@@ -1134,7 +1133,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1134 | struct ieee80211_hw *hw = &local->hw; | 1133 | struct ieee80211_hw *hw = &local->hw; |
1135 | struct ieee80211_sub_if_data *sdata; | 1134 | struct ieee80211_sub_if_data *sdata; |
1136 | struct sta_info *sta; | 1135 | struct sta_info *sta; |
1137 | int res; | 1136 | int res, i; |
1138 | 1137 | ||
1139 | #ifdef CONFIG_PM | 1138 | #ifdef CONFIG_PM |
1140 | if (local->suspended) | 1139 | if (local->suspended) |
@@ -1157,27 +1156,37 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1157 | } | 1156 | } |
1158 | #endif | 1157 | #endif |
1159 | 1158 | ||
1160 | /* restart hardware */ | 1159 | /* setup fragmentation threshold */ |
1161 | if (local->open_count) { | 1160 | drv_set_frag_threshold(local, hw->wiphy->frag_threshold); |
1162 | /* | 1161 | |
1163 | * Upon resume hardware can sometimes be goofy due to | 1162 | /* setup RTS threshold */ |
1164 | * various platform / driver / bus issues, so restarting | 1163 | drv_set_rts_threshold(local, hw->wiphy->rts_threshold); |
1165 | * the device may at times not work immediately. Propagate | 1164 | |
1166 | * the error. | 1165 | /* reset coverage class */ |
1167 | */ | 1166 | drv_set_coverage_class(local, hw->wiphy->coverage_class); |
1168 | res = drv_start(local); | 1167 | |
1169 | if (res) { | 1168 | /* everything else happens only if HW was up & running */ |
1170 | WARN(local->suspended, "Hardware became unavailable " | 1169 | if (!local->open_count) |
1171 | "upon resume. This could be a software issue " | 1170 | goto wake_up; |
1172 | "prior to suspend or a hardware issue.\n"); | ||
1173 | return res; | ||
1174 | } | ||
1175 | 1171 | ||
1176 | ieee80211_led_radio(local, true); | 1172 | /* |
1177 | ieee80211_mod_tpt_led_trig(local, | 1173 | * Upon resume hardware can sometimes be goofy due to |
1178 | IEEE80211_TPT_LEDTRIG_FL_RADIO, 0); | 1174 | * various platform / driver / bus issues, so restarting |
1175 | * the device may at times not work immediately. Propagate | ||
1176 | * the error. | ||
1177 | */ | ||
1178 | res = drv_start(local); | ||
1179 | if (res) { | ||
1180 | WARN(local->suspended, "Hardware became unavailable " | ||
1181 | "upon resume. This could be a software issue " | ||
1182 | "prior to suspend or a hardware issue.\n"); | ||
1183 | return res; | ||
1179 | } | 1184 | } |
1180 | 1185 | ||
1186 | ieee80211_led_radio(local, true); | ||
1187 | ieee80211_mod_tpt_led_trig(local, | ||
1188 | IEEE80211_TPT_LEDTRIG_FL_RADIO, 0); | ||
1189 | |||
1181 | /* add interfaces */ | 1190 | /* add interfaces */ |
1182 | list_for_each_entry(sdata, &local->interfaces, list) { | 1191 | list_for_each_entry(sdata, &local->interfaces, list) { |
1183 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 1192 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
@@ -1201,11 +1210,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1201 | } | 1210 | } |
1202 | mutex_unlock(&local->sta_mtx); | 1211 | mutex_unlock(&local->sta_mtx); |
1203 | 1212 | ||
1204 | /* setup fragmentation threshold */ | 1213 | /* reconfigure tx conf */ |
1205 | drv_set_frag_threshold(local, hw->wiphy->frag_threshold); | 1214 | for (i = 0; i < hw->queues; i++) |
1206 | 1215 | drv_conf_tx(local, i, &local->tx_conf[i]); | |
1207 | /* setup RTS threshold */ | ||
1208 | drv_set_rts_threshold(local, hw->wiphy->rts_threshold); | ||
1209 | 1216 | ||
1210 | /* reconfigure hardware */ | 1217 | /* reconfigure hardware */ |
1211 | ieee80211_hw_config(local, ~0); | 1218 | ieee80211_hw_config(local, ~0); |
@@ -1287,9 +1294,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1287 | if (ieee80211_sdata_running(sdata)) | 1294 | if (ieee80211_sdata_running(sdata)) |
1288 | ieee80211_enable_keys(sdata); | 1295 | ieee80211_enable_keys(sdata); |
1289 | 1296 | ||
1290 | #ifdef CONFIG_PM | ||
1291 | wake_up: | 1297 | wake_up: |
1292 | #endif | ||
1293 | ieee80211_wake_queues_by_reason(hw, | 1298 | ieee80211_wake_queues_by_reason(hw, |
1294 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 1299 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
1295 | 1300 | ||
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index edf8583280c9..380b9a7462b6 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | #include "ieee80211_i.h" | 26 | #include "ieee80211_i.h" |
27 | #include "rate.h" | 27 | #include "rate.h" |
28 | #include "driver-ops.h" | ||
28 | 29 | ||
29 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) | 30 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) |
30 | #define IEEE80211_AUTH_MAX_TRIES 3 | 31 | #define IEEE80211_AUTH_MAX_TRIES 3 |
@@ -427,6 +428,14 @@ ieee80211_direct_probe(struct ieee80211_work *wk) | |||
427 | struct ieee80211_sub_if_data *sdata = wk->sdata; | 428 | struct ieee80211_sub_if_data *sdata = wk->sdata; |
428 | struct ieee80211_local *local = sdata->local; | 429 | struct ieee80211_local *local = sdata->local; |
429 | 430 | ||
431 | if (!wk->probe_auth.synced) { | ||
432 | int ret = drv_tx_sync(local, sdata, wk->filter_ta, | ||
433 | IEEE80211_TX_SYNC_AUTH); | ||
434 | if (ret) | ||
435 | return WORK_ACT_TIMEOUT; | ||
436 | } | ||
437 | wk->probe_auth.synced = true; | ||
438 | |||
430 | wk->probe_auth.tries++; | 439 | wk->probe_auth.tries++; |
431 | if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { | 440 | if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { |
432 | printk(KERN_DEBUG "%s: direct probe to %pM timed out\n", | 441 | printk(KERN_DEBUG "%s: direct probe to %pM timed out\n", |
@@ -450,7 +459,8 @@ ieee80211_direct_probe(struct ieee80211_work *wk) | |||
450 | * will not answer to direct packet in unassociated state. | 459 | * will not answer to direct packet in unassociated state. |
451 | */ | 460 | */ |
452 | ieee80211_send_probe_req(sdata, NULL, wk->probe_auth.ssid, | 461 | ieee80211_send_probe_req(sdata, NULL, wk->probe_auth.ssid, |
453 | wk->probe_auth.ssid_len, NULL, 0, true); | 462 | wk->probe_auth.ssid_len, NULL, 0, |
463 | (u32) -1, true); | ||
454 | 464 | ||
455 | wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | 465 | wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; |
456 | run_again(local, wk->timeout); | 466 | run_again(local, wk->timeout); |
@@ -465,6 +475,14 @@ ieee80211_authenticate(struct ieee80211_work *wk) | |||
465 | struct ieee80211_sub_if_data *sdata = wk->sdata; | 475 | struct ieee80211_sub_if_data *sdata = wk->sdata; |
466 | struct ieee80211_local *local = sdata->local; | 476 | struct ieee80211_local *local = sdata->local; |
467 | 477 | ||
478 | if (!wk->probe_auth.synced) { | ||
479 | int ret = drv_tx_sync(local, sdata, wk->filter_ta, | ||
480 | IEEE80211_TX_SYNC_AUTH); | ||
481 | if (ret) | ||
482 | return WORK_ACT_TIMEOUT; | ||
483 | } | ||
484 | wk->probe_auth.synced = true; | ||
485 | |||
468 | wk->probe_auth.tries++; | 486 | wk->probe_auth.tries++; |
469 | if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { | 487 | if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { |
470 | printk(KERN_DEBUG "%s: authentication with %pM" | 488 | printk(KERN_DEBUG "%s: authentication with %pM" |
@@ -498,6 +516,14 @@ ieee80211_associate(struct ieee80211_work *wk) | |||
498 | struct ieee80211_sub_if_data *sdata = wk->sdata; | 516 | struct ieee80211_sub_if_data *sdata = wk->sdata; |
499 | struct ieee80211_local *local = sdata->local; | 517 | struct ieee80211_local *local = sdata->local; |
500 | 518 | ||
519 | if (!wk->assoc.synced) { | ||
520 | int ret = drv_tx_sync(local, sdata, wk->filter_ta, | ||
521 | IEEE80211_TX_SYNC_ASSOC); | ||
522 | if (ret) | ||
523 | return WORK_ACT_TIMEOUT; | ||
524 | } | ||
525 | wk->assoc.synced = true; | ||
526 | |||
501 | wk->assoc.tries++; | 527 | wk->assoc.tries++; |
502 | if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) { | 528 | if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) { |
503 | printk(KERN_DEBUG "%s: association with %pM" | 529 | printk(KERN_DEBUG "%s: association with %pM" |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 880dbe2e6f94..645437cfc464 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -488,6 +488,10 @@ int wiphy_register(struct wiphy *wiphy) | |||
488 | int i; | 488 | int i; |
489 | u16 ifmodes = wiphy->interface_modes; | 489 | u16 ifmodes = wiphy->interface_modes; |
490 | 490 | ||
491 | if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && | ||
492 | !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) | ||
493 | return -EINVAL; | ||
494 | |||
491 | if (WARN_ON(wiphy->addresses && !wiphy->n_addresses)) | 495 | if (WARN_ON(wiphy->addresses && !wiphy->n_addresses)) |
492 | return -EINVAL; | 496 | return -EINVAL; |
493 | 497 | ||
@@ -918,7 +922,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
918 | * Configure power management to the driver here so that its | 922 | * Configure power management to the driver here so that its |
919 | * correctly set also after interface type changes etc. | 923 | * correctly set also after interface type changes etc. |
920 | */ | 924 | */ |
921 | if (wdev->iftype == NL80211_IFTYPE_STATION && | 925 | if ((wdev->iftype == NL80211_IFTYPE_STATION || |
926 | wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) && | ||
922 | rdev->ops->set_power_mgmt) | 927 | rdev->ops->set_power_mgmt) |
923 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, | 928 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, |
924 | wdev->ps, | 929 | wdev->ps, |
diff --git a/net/wireless/core.h b/net/wireless/core.h index a570ff9214ec..8672e028022f 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -447,6 +447,10 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev, | |||
447 | 447 | ||
448 | u16 cfg80211_calculate_bitrate(struct rate_info *rate); | 448 | u16 cfg80211_calculate_bitrate(struct rate_info *rate); |
449 | 449 | ||
450 | int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, | ||
451 | const u8 *rates, unsigned int n_rates, | ||
452 | u32 *mask); | ||
453 | |||
450 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | 454 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, |
451 | u32 beacon_int); | 455 | u32 beacon_int); |
452 | 456 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 6a82c898f831..28d2aa109bee 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -177,6 +177,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
177 | [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, | 177 | [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, |
178 | [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 }, | 178 | [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 }, |
179 | [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED }, | 179 | [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED }, |
180 | [NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED }, | ||
180 | }; | 181 | }; |
181 | 182 | ||
182 | /* policy for the key attributes */ | 183 | /* policy for the key attributes */ |
@@ -205,6 +206,10 @@ nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { | |||
205 | [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG }, | 206 | [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG }, |
206 | [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG }, | 207 | [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG }, |
207 | [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED }, | 208 | [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED }, |
209 | [NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE] = { .type = NLA_FLAG }, | ||
210 | [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG }, | ||
211 | [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, | ||
212 | [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, | ||
208 | }; | 213 | }; |
209 | 214 | ||
210 | /* policy for GTK rekey offload attributes */ | 215 | /* policy for GTK rekey offload attributes */ |
@@ -692,8 +697,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
692 | dev->wiphy.coverage_class); | 697 | dev->wiphy.coverage_class); |
693 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | 698 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, |
694 | dev->wiphy.max_scan_ssids); | 699 | dev->wiphy.max_scan_ssids); |
700 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, | ||
701 | dev->wiphy.max_sched_scan_ssids); | ||
695 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, | 702 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, |
696 | dev->wiphy.max_scan_ie_len); | 703 | dev->wiphy.max_scan_ie_len); |
704 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, | ||
705 | dev->wiphy.max_sched_scan_ie_len); | ||
697 | 706 | ||
698 | if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) | 707 | if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) |
699 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); | 708 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); |
@@ -929,6 +938,16 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
929 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); | 938 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); |
930 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) | 939 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) |
931 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); | 940 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); |
941 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) | ||
942 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED); | ||
943 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) | ||
944 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE); | ||
945 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) | ||
946 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST); | ||
947 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) | ||
948 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE); | ||
949 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) | ||
950 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE); | ||
932 | if (dev->wiphy.wowlan.n_patterns) { | 951 | if (dev->wiphy.wowlan.n_patterns) { |
933 | struct nl80211_wowlan_pattern_support pat = { | 952 | struct nl80211_wowlan_pattern_support pat = { |
934 | .max_patterns = dev->wiphy.wowlan.n_patterns, | 953 | .max_patterns = dev->wiphy.wowlan.n_patterns, |
@@ -3306,7 +3325,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3306 | struct nlattr *attr; | 3325 | struct nlattr *attr; |
3307 | struct wiphy *wiphy; | 3326 | struct wiphy *wiphy; |
3308 | int err, tmp, n_ssids = 0, n_channels, i; | 3327 | int err, tmp, n_ssids = 0, n_channels, i; |
3309 | enum ieee80211_band band; | ||
3310 | size_t ie_len; | 3328 | size_t ie_len; |
3311 | 3329 | ||
3312 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 3330 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
@@ -3326,6 +3344,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3326 | if (!n_channels) | 3344 | if (!n_channels) |
3327 | return -EINVAL; | 3345 | return -EINVAL; |
3328 | } else { | 3346 | } else { |
3347 | enum ieee80211_band band; | ||
3329 | n_channels = 0; | 3348 | n_channels = 0; |
3330 | 3349 | ||
3331 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | 3350 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) |
@@ -3386,6 +3405,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3386 | i++; | 3405 | i++; |
3387 | } | 3406 | } |
3388 | } else { | 3407 | } else { |
3408 | enum ieee80211_band band; | ||
3409 | |||
3389 | /* all channels */ | 3410 | /* all channels */ |
3390 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 3411 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
3391 | int j; | 3412 | int j; |
@@ -3432,6 +3453,30 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3432 | request->ie_len); | 3453 | request->ie_len); |
3433 | } | 3454 | } |
3434 | 3455 | ||
3456 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | ||
3457 | if (wiphy->bands[i]) | ||
3458 | request->rates[i] = | ||
3459 | (1 << wiphy->bands[i]->n_bitrates) - 1; | ||
3460 | |||
3461 | if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) { | ||
3462 | nla_for_each_nested(attr, | ||
3463 | info->attrs[NL80211_ATTR_SCAN_SUPP_RATES], | ||
3464 | tmp) { | ||
3465 | enum ieee80211_band band = nla_type(attr); | ||
3466 | |||
3467 | if (band < 0 || band > IEEE80211_NUM_BANDS) { | ||
3468 | err = -EINVAL; | ||
3469 | goto out_free; | ||
3470 | } | ||
3471 | err = ieee80211_get_ratemask(wiphy->bands[band], | ||
3472 | nla_data(attr), | ||
3473 | nla_len(attr), | ||
3474 | &request->rates[band]); | ||
3475 | if (err) | ||
3476 | goto out_free; | ||
3477 | } | ||
3478 | } | ||
3479 | |||
3435 | request->dev = dev; | 3480 | request->dev = dev; |
3436 | request->wiphy = &rdev->wiphy; | 3481 | request->wiphy = &rdev->wiphy; |
3437 | 3482 | ||
@@ -3497,7 +3542,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
3497 | tmp) | 3542 | tmp) |
3498 | n_ssids++; | 3543 | n_ssids++; |
3499 | 3544 | ||
3500 | if (n_ssids > wiphy->max_scan_ssids) | 3545 | if (n_ssids > wiphy->max_sched_scan_ssids) |
3501 | return -EINVAL; | 3546 | return -EINVAL; |
3502 | 3547 | ||
3503 | if (info->attrs[NL80211_ATTR_IE]) | 3548 | if (info->attrs[NL80211_ATTR_IE]) |
@@ -3505,7 +3550,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
3505 | else | 3550 | else |
3506 | ie_len = 0; | 3551 | ie_len = 0; |
3507 | 3552 | ||
3508 | if (ie_len > wiphy->max_scan_ie_len) | 3553 | if (ie_len > wiphy->max_sched_scan_ie_len) |
3509 | return -EINVAL; | 3554 | return -EINVAL; |
3510 | 3555 | ||
3511 | mutex_lock(&rdev->sched_scan_mtx); | 3556 | mutex_lock(&rdev->sched_scan_mtx); |
@@ -4318,25 +4363,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
4318 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | 4363 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); |
4319 | struct ieee80211_supported_band *sband = | 4364 | struct ieee80211_supported_band *sband = |
4320 | wiphy->bands[ibss.channel->band]; | 4365 | wiphy->bands[ibss.channel->band]; |
4321 | int i, j; | 4366 | int err; |
4322 | 4367 | ||
4323 | if (n_rates == 0) | 4368 | err = ieee80211_get_ratemask(sband, rates, n_rates, |
4324 | return -EINVAL; | 4369 | &ibss.basic_rates); |
4325 | 4370 | if (err) | |
4326 | for (i = 0; i < n_rates; i++) { | 4371 | return err; |
4327 | int rate = (rates[i] & 0x7f) * 5; | ||
4328 | bool found = false; | ||
4329 | |||
4330 | for (j = 0; j < sband->n_bitrates; j++) { | ||
4331 | if (sband->bitrates[j].bitrate == rate) { | ||
4332 | found = true; | ||
4333 | ibss.basic_rates |= BIT(j); | ||
4334 | break; | ||
4335 | } | ||
4336 | } | ||
4337 | if (!found) | ||
4338 | return -EINVAL; | ||
4339 | } | ||
4340 | } | 4372 | } |
4341 | 4373 | ||
4342 | if (info->attrs[NL80211_ATTR_MCAST_RATE] && | 4374 | if (info->attrs[NL80211_ATTR_MCAST_RATE] && |
@@ -5272,6 +5304,14 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
5272 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); | 5304 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); |
5273 | if (rdev->wowlan->magic_pkt) | 5305 | if (rdev->wowlan->magic_pkt) |
5274 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); | 5306 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); |
5307 | if (rdev->wowlan->gtk_rekey_failure) | ||
5308 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE); | ||
5309 | if (rdev->wowlan->eap_identity_req) | ||
5310 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST); | ||
5311 | if (rdev->wowlan->four_way_handshake) | ||
5312 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE); | ||
5313 | if (rdev->wowlan->rfkill_release) | ||
5314 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE); | ||
5275 | if (rdev->wowlan->n_patterns) { | 5315 | if (rdev->wowlan->n_patterns) { |
5276 | struct nlattr *nl_pats, *nl_pat; | 5316 | struct nlattr *nl_pats, *nl_pat; |
5277 | int i, pat_len; | 5317 | int i, pat_len; |
@@ -5348,6 +5388,33 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
5348 | new_triggers.magic_pkt = true; | 5388 | new_triggers.magic_pkt = true; |
5349 | } | 5389 | } |
5350 | 5390 | ||
5391 | if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED]) | ||
5392 | return -EINVAL; | ||
5393 | |||
5394 | if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) { | ||
5395 | if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE)) | ||
5396 | return -EINVAL; | ||
5397 | new_triggers.gtk_rekey_failure = true; | ||
5398 | } | ||
5399 | |||
5400 | if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) { | ||
5401 | if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ)) | ||
5402 | return -EINVAL; | ||
5403 | new_triggers.eap_identity_req = true; | ||
5404 | } | ||
5405 | |||
5406 | if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) { | ||
5407 | if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE)) | ||
5408 | return -EINVAL; | ||
5409 | new_triggers.four_way_handshake = true; | ||
5410 | } | ||
5411 | |||
5412 | if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) { | ||
5413 | if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE)) | ||
5414 | return -EINVAL; | ||
5415 | new_triggers.rfkill_release = true; | ||
5416 | } | ||
5417 | |||
5351 | if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { | 5418 | if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { |
5352 | struct nlattr *pat; | 5419 | struct nlattr *pat; |
5353 | int n_patterns = 0; | 5420 | int n_patterns = 0; |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 1c4672e35144..2936cb809152 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -862,6 +862,10 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
862 | creq->n_ssids = 0; | 862 | creq->n_ssids = 0; |
863 | } | 863 | } |
864 | 864 | ||
865 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | ||
866 | if (wiphy->bands[i]) | ||
867 | creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; | ||
868 | |||
865 | rdev->scan_req = creq; | 869 | rdev->scan_req = creq; |
866 | err = rdev->ops->scan(wiphy, dev, creq); | 870 | err = rdev->ops->scan(wiphy, dev, creq); |
867 | if (err) { | 871 | if (err) { |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 4d7b83fbc32f..be75a3a0424e 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -1006,3 +1006,41 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
1006 | 1006 | ||
1007 | return -EBUSY; | 1007 | return -EBUSY; |
1008 | } | 1008 | } |
1009 | |||
1010 | int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, | ||
1011 | const u8 *rates, unsigned int n_rates, | ||
1012 | u32 *mask) | ||
1013 | { | ||
1014 | int i, j; | ||
1015 | |||
1016 | if (!sband) | ||
1017 | return -EINVAL; | ||
1018 | |||
1019 | if (n_rates == 0 || n_rates > NL80211_MAX_SUPP_RATES) | ||
1020 | return -EINVAL; | ||
1021 | |||
1022 | *mask = 0; | ||
1023 | |||
1024 | for (i = 0; i < n_rates; i++) { | ||
1025 | int rate = (rates[i] & 0x7f) * 5; | ||
1026 | bool found = false; | ||
1027 | |||
1028 | for (j = 0; j < sband->n_bitrates; j++) { | ||
1029 | if (sband->bitrates[j].bitrate == rate) { | ||
1030 | found = true; | ||
1031 | *mask |= BIT(j); | ||
1032 | break; | ||
1033 | } | ||
1034 | } | ||
1035 | if (!found) | ||
1036 | return -EINVAL; | ||
1037 | } | ||
1038 | |||
1039 | /* | ||
1040 | * mask must have at least one bit set here since we | ||
1041 | * didn't accept a 0-length rates array nor allowed | ||
1042 | * entries in the array that didn't exist | ||
1043 | */ | ||
1044 | |||
1045 | return 0; | ||
1046 | } | ||