diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-07-09 16:34:39 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-07-09 16:34:39 -0400 |
commit | 0af5491c2f6069bb6cff4260619749a90a208c98 (patch) | |
tree | a26ad1348cacd93b9e1e62be1966adaa300e4e52 /net | |
parent | 635d999fd3b9f0ddc899eaf45fc49bec65c0b8e2 (diff) | |
parent | 4d6d0ae2a088e1e054ef6d96ceb1b41523291e71 (diff) |
Merge branch 'for-john' of git://git.sipsolutions.net/mac80211-next
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 24 | ||||
-rw-r--r-- | net/mac80211/debugfs_key.c | 16 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 22 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 11 | ||||
-rw-r--r-- | net/mac80211/iface.c | 258 | ||||
-rw-r--r-- | net/mac80211/main.c | 17 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 4 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 28 | ||||
-rw-r--r-- | net/mac80211/trace.h | 7 | ||||
-rw-r--r-- | net/mac80211/tx.c | 16 | ||||
-rw-r--r-- | net/mac80211/util.c | 49 | ||||
-rw-r--r-- | net/wireless/Makefile | 2 | ||||
-rw-r--r-- | net/wireless/ap.c | 46 | ||||
-rw-r--r-- | net/wireless/chan.c | 62 | ||||
-rw-r--r-- | net/wireless/core.c | 84 | ||||
-rw-r--r-- | net/wireless/core.h | 64 | ||||
-rw-r--r-- | net/wireless/ibss.c | 11 | ||||
-rw-r--r-- | net/wireless/mesh.c | 30 | ||||
-rw-r--r-- | net/wireless/mlme.c | 17 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 65 | ||||
-rw-r--r-- | net/wireless/reg.c | 5 | ||||
-rw-r--r-- | net/wireless/util.c | 156 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 9 |
23 files changed, 746 insertions, 257 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c2a2dcbfdf01..ccbe2413142a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -2668,8 +2668,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
2668 | tf->u.setup_req.capability = | 2668 | tf->u.setup_req.capability = |
2669 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2669 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
2670 | 2670 | ||
2671 | ieee80211_add_srates_ie(&sdata->vif, skb, false); | 2671 | ieee80211_add_srates_ie(sdata, skb, false); |
2672 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); | 2672 | ieee80211_add_ext_srates_ie(sdata, skb, false); |
2673 | ieee80211_tdls_add_ext_capab(skb); | 2673 | ieee80211_tdls_add_ext_capab(skb); |
2674 | break; | 2674 | break; |
2675 | case WLAN_TDLS_SETUP_RESPONSE: | 2675 | case WLAN_TDLS_SETUP_RESPONSE: |
@@ -2682,8 +2682,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
2682 | tf->u.setup_resp.capability = | 2682 | tf->u.setup_resp.capability = |
2683 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2683 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
2684 | 2684 | ||
2685 | ieee80211_add_srates_ie(&sdata->vif, skb, false); | 2685 | ieee80211_add_srates_ie(sdata, skb, false); |
2686 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); | 2686 | ieee80211_add_ext_srates_ie(sdata, skb, false); |
2687 | ieee80211_tdls_add_ext_capab(skb); | 2687 | ieee80211_tdls_add_ext_capab(skb); |
2688 | break; | 2688 | break; |
2689 | case WLAN_TDLS_SETUP_CONFIRM: | 2689 | case WLAN_TDLS_SETUP_CONFIRM: |
@@ -2743,8 +2743,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | |||
2743 | mgmt->u.action.u.tdls_discover_resp.capability = | 2743 | mgmt->u.action.u.tdls_discover_resp.capability = |
2744 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2744 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
2745 | 2745 | ||
2746 | ieee80211_add_srates_ie(&sdata->vif, skb, false); | 2746 | ieee80211_add_srates_ie(sdata, skb, false); |
2747 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); | 2747 | ieee80211_add_ext_srates_ie(sdata, skb, false); |
2748 | ieee80211_tdls_add_ext_capab(skb); | 2748 | ieee80211_tdls_add_ext_capab(skb); |
2749 | break; | 2749 | break; |
2750 | default: | 2750 | default: |
@@ -2980,14 +2980,14 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | |||
2980 | return 0; | 2980 | return 0; |
2981 | } | 2981 | } |
2982 | 2982 | ||
2983 | static struct ieee80211_channel * | 2983 | static void ieee80211_set_monitor_enabled(struct wiphy *wiphy, bool enabled) |
2984 | ieee80211_wiphy_get_channel(struct wiphy *wiphy, | ||
2985 | enum nl80211_channel_type *type) | ||
2986 | { | 2984 | { |
2987 | struct ieee80211_local *local = wiphy_priv(wiphy); | 2985 | struct ieee80211_local *local = wiphy_priv(wiphy); |
2988 | 2986 | ||
2989 | *type = local->_oper_channel_type; | 2987 | if (enabled) |
2990 | return local->oper_channel; | 2988 | WARN_ON(ieee80211_add_virtual_monitor(local)); |
2989 | else | ||
2990 | ieee80211_del_virtual_monitor(local); | ||
2991 | } | 2991 | } |
2992 | 2992 | ||
2993 | #ifdef CONFIG_PM | 2993 | #ifdef CONFIG_PM |
@@ -3063,8 +3063,8 @@ struct cfg80211_ops mac80211_config_ops = { | |||
3063 | .tdls_oper = ieee80211_tdls_oper, | 3063 | .tdls_oper = ieee80211_tdls_oper, |
3064 | .tdls_mgmt = ieee80211_tdls_mgmt, | 3064 | .tdls_mgmt = ieee80211_tdls_mgmt, |
3065 | .probe_client = ieee80211_probe_client, | 3065 | .probe_client = ieee80211_probe_client, |
3066 | .get_channel = ieee80211_wiphy_get_channel, | ||
3067 | .set_noack_map = ieee80211_set_noack_map, | 3066 | .set_noack_map = ieee80211_set_noack_map, |
3067 | .set_monitor_enabled = ieee80211_set_monitor_enabled, | ||
3068 | #ifdef CONFIG_PM | 3068 | #ifdef CONFIG_PM |
3069 | .set_wakeup = ieee80211_set_wakeup, | 3069 | .set_wakeup = ieee80211_set_wakeup, |
3070 | #endif | 3070 | #endif |
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 7932767bb482..090d08ff22c4 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
@@ -283,6 +283,11 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
283 | 283 | ||
284 | lockdep_assert_held(&sdata->local->key_mtx); | 284 | lockdep_assert_held(&sdata->local->key_mtx); |
285 | 285 | ||
286 | if (sdata->debugfs.default_unicast_key) { | ||
287 | debugfs_remove(sdata->debugfs.default_unicast_key); | ||
288 | sdata->debugfs.default_unicast_key = NULL; | ||
289 | } | ||
290 | |||
286 | if (sdata->default_unicast_key) { | 291 | if (sdata->default_unicast_key) { |
287 | key = key_mtx_dereference(sdata->local, | 292 | key = key_mtx_dereference(sdata->local, |
288 | sdata->default_unicast_key); | 293 | sdata->default_unicast_key); |
@@ -290,9 +295,11 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
290 | sdata->debugfs.default_unicast_key = | 295 | sdata->debugfs.default_unicast_key = |
291 | debugfs_create_symlink("default_unicast_key", | 296 | debugfs_create_symlink("default_unicast_key", |
292 | sdata->debugfs.dir, buf); | 297 | sdata->debugfs.dir, buf); |
293 | } else { | 298 | } |
294 | debugfs_remove(sdata->debugfs.default_unicast_key); | 299 | |
295 | sdata->debugfs.default_unicast_key = NULL; | 300 | if (sdata->debugfs.default_multicast_key) { |
301 | debugfs_remove(sdata->debugfs.default_multicast_key); | ||
302 | sdata->debugfs.default_multicast_key = NULL; | ||
296 | } | 303 | } |
297 | 304 | ||
298 | if (sdata->default_multicast_key) { | 305 | if (sdata->default_multicast_key) { |
@@ -302,9 +309,6 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
302 | sdata->debugfs.default_multicast_key = | 309 | sdata->debugfs.default_multicast_key = |
303 | debugfs_create_symlink("default_multicast_key", | 310 | debugfs_create_symlink("default_multicast_key", |
304 | sdata->debugfs.dir, buf); | 311 | sdata->debugfs.dir, buf); |
305 | } else { | ||
306 | debugfs_remove(sdata->debugfs.default_multicast_key); | ||
307 | sdata->debugfs.default_multicast_key = NULL; | ||
308 | } | 312 | } |
309 | } | 313 | } |
310 | 314 | ||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 44e8c1242781..df9203199102 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -27,14 +27,6 @@ static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb) | |||
27 | local->ops->tx(&local->hw, skb); | 27 | local->ops->tx(&local->hw, skb); |
28 | } | 28 | } |
29 | 29 | ||
30 | static inline void drv_tx_frags(struct ieee80211_local *local, | ||
31 | struct ieee80211_vif *vif, | ||
32 | struct ieee80211_sta *sta, | ||
33 | struct sk_buff_head *skbs) | ||
34 | { | ||
35 | local->ops->tx_frags(&local->hw, vif, sta, skbs); | ||
36 | } | ||
37 | |||
38 | static inline void drv_get_et_strings(struct ieee80211_sub_if_data *sdata, | 30 | static inline void drv_get_et_strings(struct ieee80211_sub_if_data *sdata, |
39 | u32 sset, u8 *data) | 31 | u32 sset, u8 *data) |
40 | { | 32 | { |
@@ -860,4 +852,18 @@ static inline int drv_get_rssi(struct ieee80211_local *local, | |||
860 | 852 | ||
861 | return ret; | 853 | return ret; |
862 | } | 854 | } |
855 | |||
856 | static inline void drv_mgd_prepare_tx(struct ieee80211_local *local, | ||
857 | struct ieee80211_sub_if_data *sdata) | ||
858 | { | ||
859 | might_sleep(); | ||
860 | |||
861 | check_sdata_in_driver(sdata); | ||
862 | WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION); | ||
863 | |||
864 | trace_drv_mgd_prepare_tx(local, sdata); | ||
865 | if (local->ops->mgd_prepare_tx) | ||
866 | local->ops->mgd_prepare_tx(&local->hw, &sdata->vif); | ||
867 | trace_drv_return_void(local); | ||
868 | } | ||
863 | #endif /* __MAC80211_DRIVER_OPS */ | 869 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f834a005e1c5..e0423f8c0ce1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -1284,7 +1284,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
1284 | enum nl80211_iftype type); | 1284 | enum nl80211_iftype type); |
1285 | void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); | 1285 | void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); |
1286 | void ieee80211_remove_interfaces(struct ieee80211_local *local); | 1286 | void ieee80211_remove_interfaces(struct ieee80211_local *local); |
1287 | u32 __ieee80211_recalc_idle(struct ieee80211_local *local); | ||
1288 | void ieee80211_recalc_idle(struct ieee80211_local *local); | 1287 | void ieee80211_recalc_idle(struct ieee80211_local *local); |
1289 | void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | 1288 | void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, |
1290 | const int offset); | 1289 | const int offset); |
@@ -1481,6 +1480,16 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
1481 | struct ieee80211_channel *channel, | 1480 | struct ieee80211_channel *channel, |
1482 | enum nl80211_channel_type channel_type, | 1481 | enum nl80211_channel_type channel_type, |
1483 | u16 prot_mode); | 1482 | u16 prot_mode); |
1483 | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | ||
1484 | u32 cap); | ||
1485 | int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | ||
1486 | struct sk_buff *skb, bool need_basic); | ||
1487 | int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | ||
1488 | struct sk_buff *skb, bool need_basic); | ||
1489 | |||
1490 | /* virtual monitor */ | ||
1491 | int ieee80211_add_virtual_monitor(struct ieee80211_local *local); | ||
1492 | void ieee80211_del_virtual_monitor(struct ieee80211_local *local); | ||
1484 | 1493 | ||
1485 | /* channel management */ | 1494 | /* channel management */ |
1486 | enum ieee80211_chan_mode { | 1495 | enum ieee80211_chan_mode { |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 58c2ab3d483a..fbef7a1ada7a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -43,6 +43,127 @@ | |||
43 | */ | 43 | */ |
44 | 44 | ||
45 | 45 | ||
46 | static u32 ieee80211_idle_off(struct ieee80211_local *local, | ||
47 | const char *reason) | ||
48 | { | ||
49 | if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) | ||
50 | return 0; | ||
51 | |||
52 | local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; | ||
53 | return IEEE80211_CONF_CHANGE_IDLE; | ||
54 | } | ||
55 | |||
56 | static u32 ieee80211_idle_on(struct ieee80211_local *local) | ||
57 | { | ||
58 | if (local->hw.conf.flags & IEEE80211_CONF_IDLE) | ||
59 | return 0; | ||
60 | |||
61 | drv_flush(local, false); | ||
62 | |||
63 | local->hw.conf.flags |= IEEE80211_CONF_IDLE; | ||
64 | return IEEE80211_CONF_CHANGE_IDLE; | ||
65 | } | ||
66 | |||
67 | static u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | ||
68 | { | ||
69 | struct ieee80211_sub_if_data *sdata; | ||
70 | int count = 0; | ||
71 | bool working = false, scanning = false; | ||
72 | unsigned int led_trig_start = 0, led_trig_stop = 0; | ||
73 | struct ieee80211_roc_work *roc; | ||
74 | |||
75 | #ifdef CONFIG_PROVE_LOCKING | ||
76 | WARN_ON(debug_locks && !lockdep_rtnl_is_held() && | ||
77 | !lockdep_is_held(&local->iflist_mtx)); | ||
78 | #endif | ||
79 | lockdep_assert_held(&local->mtx); | ||
80 | |||
81 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
82 | if (!ieee80211_sdata_running(sdata)) { | ||
83 | sdata->vif.bss_conf.idle = true; | ||
84 | continue; | ||
85 | } | ||
86 | |||
87 | sdata->old_idle = sdata->vif.bss_conf.idle; | ||
88 | |||
89 | /* do not count disabled managed interfaces */ | ||
90 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
91 | !sdata->u.mgd.associated && | ||
92 | !sdata->u.mgd.auth_data && | ||
93 | !sdata->u.mgd.assoc_data) { | ||
94 | sdata->vif.bss_conf.idle = true; | ||
95 | continue; | ||
96 | } | ||
97 | /* do not count unused IBSS interfaces */ | ||
98 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | ||
99 | !sdata->u.ibss.ssid_len) { | ||
100 | sdata->vif.bss_conf.idle = true; | ||
101 | continue; | ||
102 | } | ||
103 | /* count everything else */ | ||
104 | sdata->vif.bss_conf.idle = false; | ||
105 | count++; | ||
106 | } | ||
107 | |||
108 | if (!local->ops->remain_on_channel) { | ||
109 | list_for_each_entry(roc, &local->roc_list, list) { | ||
110 | working = true; | ||
111 | roc->sdata->vif.bss_conf.idle = false; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | if (local->scan_sdata && | ||
116 | !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { | ||
117 | scanning = true; | ||
118 | local->scan_sdata->vif.bss_conf.idle = false; | ||
119 | } | ||
120 | |||
121 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
122 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | ||
123 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
124 | continue; | ||
125 | if (sdata->old_idle == sdata->vif.bss_conf.idle) | ||
126 | continue; | ||
127 | if (!ieee80211_sdata_running(sdata)) | ||
128 | continue; | ||
129 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
130 | } | ||
131 | |||
132 | if (working || scanning) | ||
133 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
134 | else | ||
135 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
136 | |||
137 | if (count) | ||
138 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
139 | else | ||
140 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
141 | |||
142 | ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); | ||
143 | |||
144 | if (working) | ||
145 | return ieee80211_idle_off(local, "working"); | ||
146 | if (scanning) | ||
147 | return ieee80211_idle_off(local, "scanning"); | ||
148 | if (!count) | ||
149 | return ieee80211_idle_on(local); | ||
150 | else | ||
151 | return ieee80211_idle_off(local, "in use"); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | void ieee80211_recalc_idle(struct ieee80211_local *local) | ||
157 | { | ||
158 | u32 chg; | ||
159 | |||
160 | mutex_lock(&local->iflist_mtx); | ||
161 | chg = __ieee80211_recalc_idle(local); | ||
162 | mutex_unlock(&local->iflist_mtx); | ||
163 | if (chg) | ||
164 | ieee80211_hw_config(local, chg); | ||
165 | } | ||
166 | |||
46 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | 167 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) |
47 | { | 168 | { |
48 | int meshhdrlen; | 169 | int meshhdrlen; |
@@ -209,7 +330,7 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) | |||
209 | sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; | 330 | sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; |
210 | } | 331 | } |
211 | 332 | ||
212 | static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | 333 | int ieee80211_add_virtual_monitor(struct ieee80211_local *local) |
213 | { | 334 | { |
214 | struct ieee80211_sub_if_data *sdata; | 335 | struct ieee80211_sub_if_data *sdata; |
215 | int ret; | 336 | int ret; |
@@ -250,7 +371,7 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | |||
250 | return 0; | 371 | return 0; |
251 | } | 372 | } |
252 | 373 | ||
253 | static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) | 374 | void ieee80211_del_virtual_monitor(struct ieee80211_local *local) |
254 | { | 375 | { |
255 | struct ieee80211_sub_if_data *sdata; | 376 | struct ieee80211_sub_if_data *sdata; |
256 | 377 | ||
@@ -366,12 +487,6 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
366 | break; | 487 | break; |
367 | } | 488 | } |
368 | 489 | ||
369 | if (local->monitors == 0 && local->open_count == 0) { | ||
370 | res = ieee80211_add_virtual_monitor(local); | ||
371 | if (res) | ||
372 | goto err_stop; | ||
373 | } | ||
374 | |||
375 | /* must be before the call to ieee80211_configure_filter */ | 490 | /* must be before the call to ieee80211_configure_filter */ |
376 | local->monitors++; | 491 | local->monitors++; |
377 | if (local->monitors == 1) { | 492 | if (local->monitors == 1) { |
@@ -386,8 +501,6 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
386 | break; | 501 | break; |
387 | default: | 502 | default: |
388 | if (coming_up) { | 503 | if (coming_up) { |
389 | ieee80211_del_virtual_monitor(local); | ||
390 | |||
391 | res = drv_add_interface(local, sdata); | 504 | res = drv_add_interface(local, sdata); |
392 | if (res) | 505 | if (res) |
393 | goto err_stop; | 506 | goto err_stop; |
@@ -622,7 +735,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
622 | if (local->monitors == 0) { | 735 | if (local->monitors == 0) { |
623 | local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; | 736 | local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; |
624 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; | 737 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; |
625 | ieee80211_del_virtual_monitor(local); | ||
626 | } | 738 | } |
627 | 739 | ||
628 | ieee80211_adjust_monitor_flags(sdata, -1); | 740 | ieee80211_adjust_monitor_flags(sdata, -1); |
@@ -696,9 +808,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
696 | } | 808 | } |
697 | } | 809 | } |
698 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 810 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
699 | |||
700 | if (local->monitors == local->open_count && local->monitors > 0) | ||
701 | ieee80211_add_virtual_monitor(local); | ||
702 | } | 811 | } |
703 | 812 | ||
704 | static int ieee80211_stop(struct net_device *dev) | 813 | static int ieee80211_stop(struct net_device *dev) |
@@ -1403,127 +1512,6 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) | |||
1403 | list_del(&unreg_list); | 1512 | list_del(&unreg_list); |
1404 | } | 1513 | } |
1405 | 1514 | ||
1406 | static u32 ieee80211_idle_off(struct ieee80211_local *local, | ||
1407 | const char *reason) | ||
1408 | { | ||
1409 | if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) | ||
1410 | return 0; | ||
1411 | |||
1412 | local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; | ||
1413 | return IEEE80211_CONF_CHANGE_IDLE; | ||
1414 | } | ||
1415 | |||
1416 | static u32 ieee80211_idle_on(struct ieee80211_local *local) | ||
1417 | { | ||
1418 | if (local->hw.conf.flags & IEEE80211_CONF_IDLE) | ||
1419 | return 0; | ||
1420 | |||
1421 | drv_flush(local, false); | ||
1422 | |||
1423 | local->hw.conf.flags |= IEEE80211_CONF_IDLE; | ||
1424 | return IEEE80211_CONF_CHANGE_IDLE; | ||
1425 | } | ||
1426 | |||
1427 | u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | ||
1428 | { | ||
1429 | struct ieee80211_sub_if_data *sdata; | ||
1430 | int count = 0; | ||
1431 | bool working = false, scanning = false; | ||
1432 | unsigned int led_trig_start = 0, led_trig_stop = 0; | ||
1433 | struct ieee80211_roc_work *roc; | ||
1434 | |||
1435 | #ifdef CONFIG_PROVE_LOCKING | ||
1436 | WARN_ON(debug_locks && !lockdep_rtnl_is_held() && | ||
1437 | !lockdep_is_held(&local->iflist_mtx)); | ||
1438 | #endif | ||
1439 | lockdep_assert_held(&local->mtx); | ||
1440 | |||
1441 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1442 | if (!ieee80211_sdata_running(sdata)) { | ||
1443 | sdata->vif.bss_conf.idle = true; | ||
1444 | continue; | ||
1445 | } | ||
1446 | |||
1447 | sdata->old_idle = sdata->vif.bss_conf.idle; | ||
1448 | |||
1449 | /* do not count disabled managed interfaces */ | ||
1450 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
1451 | !sdata->u.mgd.associated && | ||
1452 | !sdata->u.mgd.auth_data && | ||
1453 | !sdata->u.mgd.assoc_data) { | ||
1454 | sdata->vif.bss_conf.idle = true; | ||
1455 | continue; | ||
1456 | } | ||
1457 | /* do not count unused IBSS interfaces */ | ||
1458 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | ||
1459 | !sdata->u.ibss.ssid_len) { | ||
1460 | sdata->vif.bss_conf.idle = true; | ||
1461 | continue; | ||
1462 | } | ||
1463 | /* count everything else */ | ||
1464 | sdata->vif.bss_conf.idle = false; | ||
1465 | count++; | ||
1466 | } | ||
1467 | |||
1468 | if (!local->ops->remain_on_channel) { | ||
1469 | list_for_each_entry(roc, &local->roc_list, list) { | ||
1470 | working = true; | ||
1471 | roc->sdata->vif.bss_conf.idle = false; | ||
1472 | } | ||
1473 | } | ||
1474 | |||
1475 | if (local->scan_sdata && | ||
1476 | !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { | ||
1477 | scanning = true; | ||
1478 | local->scan_sdata->vif.bss_conf.idle = false; | ||
1479 | } | ||
1480 | |||
1481 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1482 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | ||
1483 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
1484 | continue; | ||
1485 | if (sdata->old_idle == sdata->vif.bss_conf.idle) | ||
1486 | continue; | ||
1487 | if (!ieee80211_sdata_running(sdata)) | ||
1488 | continue; | ||
1489 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
1490 | } | ||
1491 | |||
1492 | if (working || scanning) | ||
1493 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
1494 | else | ||
1495 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
1496 | |||
1497 | if (count) | ||
1498 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
1499 | else | ||
1500 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
1501 | |||
1502 | ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); | ||
1503 | |||
1504 | if (working) | ||
1505 | return ieee80211_idle_off(local, "working"); | ||
1506 | if (scanning) | ||
1507 | return ieee80211_idle_off(local, "scanning"); | ||
1508 | if (!count) | ||
1509 | return ieee80211_idle_on(local); | ||
1510 | else | ||
1511 | return ieee80211_idle_off(local, "in use"); | ||
1512 | |||
1513 | return 0; | ||
1514 | } | ||
1515 | |||
1516 | void ieee80211_recalc_idle(struct ieee80211_local *local) | ||
1517 | { | ||
1518 | u32 chg; | ||
1519 | |||
1520 | mutex_lock(&local->iflist_mtx); | ||
1521 | chg = __ieee80211_recalc_idle(local); | ||
1522 | mutex_unlock(&local->iflist_mtx); | ||
1523 | if (chg) | ||
1524 | ieee80211_hw_config(local, chg); | ||
1525 | } | ||
1526 | |||
1527 | static int netdev_notify(struct notifier_block *nb, | 1515 | static int netdev_notify(struct notifier_block *nb, |
1528 | unsigned long state, | 1516 | unsigned long state, |
1529 | void *ndev) | 1517 | void *ndev) |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0b040fb73673..c794101f8987 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -587,7 +587,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
587 | 587 | ||
588 | local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); | 588 | local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); |
589 | 589 | ||
590 | BUG_ON(!ops->tx && !ops->tx_frags); | 590 | BUG_ON(!ops->tx); |
591 | BUG_ON(!ops->start); | 591 | BUG_ON(!ops->start); |
592 | BUG_ON(!ops->stop); | 592 | BUG_ON(!ops->stop); |
593 | BUG_ON(!ops->config); | 593 | BUG_ON(!ops->config); |
@@ -688,7 +688,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
688 | int result, i; | 688 | int result, i; |
689 | enum ieee80211_band band; | 689 | enum ieee80211_band band; |
690 | int channels, max_bitrates; | 690 | int channels, max_bitrates; |
691 | bool supp_ht; | 691 | bool supp_ht, supp_vht; |
692 | netdev_features_t feature_whitelist; | 692 | netdev_features_t feature_whitelist; |
693 | static const u32 cipher_suites[] = { | 693 | static const u32 cipher_suites[] = { |
694 | /* keep WEP first, it may be removed below */ | 694 | /* keep WEP first, it may be removed below */ |
@@ -706,12 +706,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
706 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) | 706 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) |
707 | return -EINVAL; | 707 | return -EINVAL; |
708 | 708 | ||
709 | if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) | ||
710 | #ifdef CONFIG_PM | 709 | #ifdef CONFIG_PM |
711 | && (!local->ops->suspend || !local->ops->resume) | 710 | if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) && |
712 | #endif | 711 | (!local->ops->suspend || !local->ops->resume)) |
713 | ) | ||
714 | return -EINVAL; | 712 | return -EINVAL; |
713 | #endif | ||
715 | 714 | ||
716 | if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan) | 715 | if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan) |
717 | return -EINVAL; | 716 | return -EINVAL; |
@@ -733,6 +732,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
733 | channels = 0; | 732 | channels = 0; |
734 | max_bitrates = 0; | 733 | max_bitrates = 0; |
735 | supp_ht = false; | 734 | supp_ht = false; |
735 | supp_vht = false; | ||
736 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 736 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
737 | struct ieee80211_supported_band *sband; | 737 | struct ieee80211_supported_band *sband; |
738 | 738 | ||
@@ -750,6 +750,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
750 | if (max_bitrates < sband->n_bitrates) | 750 | if (max_bitrates < sband->n_bitrates) |
751 | max_bitrates = sband->n_bitrates; | 751 | max_bitrates = sband->n_bitrates; |
752 | supp_ht = supp_ht || sband->ht_cap.ht_supported; | 752 | supp_ht = supp_ht || sband->ht_cap.ht_supported; |
753 | supp_vht = supp_vht || sband->vht_cap.vht_supported; | ||
753 | } | 754 | } |
754 | 755 | ||
755 | local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + | 756 | local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + |
@@ -825,6 +826,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
825 | if (supp_ht) | 826 | if (supp_ht) |
826 | local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); | 827 | local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); |
827 | 828 | ||
829 | if (supp_vht) | ||
830 | local->scan_ies_len += | ||
831 | 2 + sizeof(struct ieee80211_vht_capabilities); | ||
832 | |||
828 | if (!local->ops->hw_scan) { | 833 | if (!local->ops->hw_scan) { |
829 | /* For hw_scan, driver needs to set these up. */ | 834 | /* For hw_scan, driver needs to set these up. */ |
830 | local->hw.wiphy->max_scan_ssids = 4; | 835 | local->hw.wiphy->max_scan_ssids = 4; |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index a1dbd1540276..425685914d7d 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -258,8 +258,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
258 | pos = skb_put(skb, 2); | 258 | pos = skb_put(skb, 2); |
259 | memcpy(pos + 2, &plid, 2); | 259 | memcpy(pos + 2, &plid, 2); |
260 | } | 260 | } |
261 | if (ieee80211_add_srates_ie(&sdata->vif, skb, true) || | 261 | if (ieee80211_add_srates_ie(sdata, skb, true) || |
262 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) || | 262 | ieee80211_add_ext_srates_ie(sdata, skb, true) || |
263 | mesh_add_rsn_ie(skb, sdata) || | 263 | mesh_add_rsn_ie(skb, sdata) || |
264 | mesh_add_meshid_ie(skb, sdata) || | 264 | mesh_add_meshid_ie(skb, sdata) || |
265 | mesh_add_meshconf_ie(skb, sdata)) | 265 | mesh_add_meshconf_ie(skb, sdata)) |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index aa69a331f374..f49f14f8ba82 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -541,6 +541,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
541 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | 541 | memcpy(pos, assoc_data->ie + offset, noffset - offset); |
542 | } | 542 | } |
543 | 543 | ||
544 | drv_mgd_prepare_tx(local, sdata); | ||
545 | |||
544 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 546 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
545 | ieee80211_tx_skb(sdata, skb); | 547 | ieee80211_tx_skb(sdata, skb); |
546 | } | 548 | } |
@@ -580,6 +582,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
580 | if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) | 582 | if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) |
581 | IEEE80211_SKB_CB(skb)->flags |= | 583 | IEEE80211_SKB_CB(skb)->flags |= |
582 | IEEE80211_TX_INTFL_DONT_ENCRYPT; | 584 | IEEE80211_TX_INTFL_DONT_ENCRYPT; |
585 | |||
586 | drv_mgd_prepare_tx(local, sdata); | ||
587 | |||
583 | ieee80211_tx_skb(sdata, skb); | 588 | ieee80211_tx_skb(sdata, skb); |
584 | } | 589 | } |
585 | } | 590 | } |
@@ -902,9 +907,6 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata) | |||
902 | if (!mgd->associated) | 907 | if (!mgd->associated) |
903 | return false; | 908 | return false; |
904 | 909 | ||
905 | if (!mgd->associated->beacon_ies) | ||
906 | return false; | ||
907 | |||
908 | if (mgd->flags & (IEEE80211_STA_BEACON_POLL | | 910 | if (mgd->flags & (IEEE80211_STA_BEACON_POLL | |
909 | IEEE80211_STA_CONNECTION_POLL)) | 911 | IEEE80211_STA_CONNECTION_POLL)) |
910 | return false; | 912 | return false; |
@@ -1362,6 +1364,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1362 | } | 1364 | } |
1363 | mutex_unlock(&local->sta_mtx); | 1365 | mutex_unlock(&local->sta_mtx); |
1364 | 1366 | ||
1367 | /* flush out any pending frame (e.g. DELBA) before deauth/disassoc */ | ||
1368 | if (tx) | ||
1369 | drv_flush(local, false); | ||
1370 | |||
1365 | /* deauthenticate/disassociate now */ | 1371 | /* deauthenticate/disassociate now */ |
1366 | if (tx || frame_buf) | 1372 | if (tx || frame_buf) |
1367 | ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype, | 1373 | ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype, |
@@ -1610,6 +1616,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
1610 | { | 1616 | { |
1611 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 1617 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
1612 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1618 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1619 | struct cfg80211_bss *cbss; | ||
1613 | struct sk_buff *skb; | 1620 | struct sk_buff *skb; |
1614 | const u8 *ssid; | 1621 | const u8 *ssid; |
1615 | int ssid_len; | 1622 | int ssid_len; |
@@ -1619,16 +1626,22 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
1619 | 1626 | ||
1620 | ASSERT_MGD_MTX(ifmgd); | 1627 | ASSERT_MGD_MTX(ifmgd); |
1621 | 1628 | ||
1622 | if (!ifmgd->associated) | 1629 | if (ifmgd->associated) |
1630 | cbss = ifmgd->associated; | ||
1631 | else if (ifmgd->auth_data) | ||
1632 | cbss = ifmgd->auth_data->bss; | ||
1633 | else if (ifmgd->assoc_data) | ||
1634 | cbss = ifmgd->assoc_data->bss; | ||
1635 | else | ||
1623 | return NULL; | 1636 | return NULL; |
1624 | 1637 | ||
1625 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | 1638 | ssid = ieee80211_bss_get_ie(cbss, WLAN_EID_SSID); |
1626 | if (WARN_ON_ONCE(ssid == NULL)) | 1639 | if (WARN_ON_ONCE(ssid == NULL)) |
1627 | ssid_len = 0; | 1640 | ssid_len = 0; |
1628 | else | 1641 | else |
1629 | ssid_len = ssid[1]; | 1642 | ssid_len = ssid[1]; |
1630 | 1643 | ||
1631 | skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, | 1644 | skb = ieee80211_build_probe_req(sdata, cbss->bssid, |
1632 | (u32) -1, ssid + 2, ssid_len, | 1645 | (u32) -1, ssid + 2, ssid_len, |
1633 | NULL, 0, true); | 1646 | NULL, 0, true); |
1634 | 1647 | ||
@@ -1747,6 +1760,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | |||
1747 | if (!elems.challenge) | 1760 | if (!elems.challenge) |
1748 | return; | 1761 | return; |
1749 | auth_data->expected_transaction = 4; | 1762 | auth_data->expected_transaction = 4; |
1763 | drv_mgd_prepare_tx(sdata->local, sdata); | ||
1750 | ieee80211_send_auth(sdata, 3, auth_data->algorithm, | 1764 | ieee80211_send_auth(sdata, 3, auth_data->algorithm, |
1751 | elems.challenge - 2, elems.challenge_len + 2, | 1765 | elems.challenge - 2, elems.challenge_len + 2, |
1752 | auth_data->bss->bssid, auth_data->bss->bssid, | 1766 | auth_data->bss->bssid, auth_data->bss->bssid, |
@@ -2630,6 +2644,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
2630 | return -ETIMEDOUT; | 2644 | return -ETIMEDOUT; |
2631 | } | 2645 | } |
2632 | 2646 | ||
2647 | drv_mgd_prepare_tx(local, sdata); | ||
2648 | |||
2633 | if (auth_data->bss->proberesp_ies) { | 2649 | if (auth_data->bss->proberesp_ies) { |
2634 | sdata_info(sdata, "send auth to %pM (try %d/%d)\n", | 2650 | sdata_info(sdata, "send auth to %pM (try %d/%d)\n", |
2635 | auth_data->bss->bssid, auth_data->tries, | 2651 | auth_data->bss->bssid, auth_data->tries, |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 2e60f4acd027..e1e9d10ec2e7 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -1244,6 +1244,13 @@ TRACE_EVENT(drv_get_rssi, | |||
1244 | ) | 1244 | ) |
1245 | ); | 1245 | ); |
1246 | 1246 | ||
1247 | DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx, | ||
1248 | TP_PROTO(struct ieee80211_local *local, | ||
1249 | struct ieee80211_sub_if_data *sdata), | ||
1250 | |||
1251 | TP_ARGS(local, sdata) | ||
1252 | ); | ||
1253 | |||
1247 | /* | 1254 | /* |
1248 | * Tracing for API calls that drivers call. | 1255 | * Tracing for API calls that drivers call. |
1249 | */ | 1256 | */ |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ec8f53467374..c9d2175d15c1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -140,6 +140,8 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, | |||
140 | if (r->flags & IEEE80211_RATE_MANDATORY_A) | 140 | if (r->flags & IEEE80211_RATE_MANDATORY_A) |
141 | mrate = r->bitrate; | 141 | mrate = r->bitrate; |
142 | break; | 142 | break; |
143 | case IEEE80211_BAND_60GHZ: | ||
144 | /* TODO, for now fall through */ | ||
143 | case IEEE80211_NUM_BANDS: | 145 | case IEEE80211_NUM_BANDS: |
144 | WARN_ON(1); | 146 | WARN_ON(1); |
145 | break; | 147 | break; |
@@ -957,8 +959,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
957 | info->control.rates[1].idx = -1; | 959 | info->control.rates[1].idx = -1; |
958 | info->control.rates[2].idx = -1; | 960 | info->control.rates[2].idx = -1; |
959 | info->control.rates[3].idx = -1; | 961 | info->control.rates[3].idx = -1; |
960 | info->control.rates[4].idx = -1; | 962 | BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 4); |
961 | BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5); | ||
962 | info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; | 963 | info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; |
963 | } else { | 964 | } else { |
964 | hdr->frame_control &= ~morefrags; | 965 | hdr->frame_control &= ~morefrags; |
@@ -1293,11 +1294,8 @@ static bool __ieee80211_tx(struct ieee80211_local *local, | |||
1293 | break; | 1294 | break; |
1294 | } | 1295 | } |
1295 | 1296 | ||
1296 | if (local->ops->tx_frags) | 1297 | result = ieee80211_tx_frags(local, vif, pubsta, skbs, |
1297 | drv_tx_frags(local, vif, pubsta, skbs); | 1298 | txpending); |
1298 | else | ||
1299 | result = ieee80211_tx_frags(local, vif, pubsta, skbs, | ||
1300 | txpending); | ||
1301 | 1299 | ||
1302 | ieee80211_tpt_led_trig_tx(local, fc, led_len); | 1300 | ieee80211_tpt_led_trig_tx(local, fc, led_len); |
1303 | ieee80211_led_tx(local, 1); | 1301 | ieee80211_led_tx(local, 1); |
@@ -2420,9 +2418,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2420 | *pos++ = WLAN_EID_SSID; | 2418 | *pos++ = WLAN_EID_SSID; |
2421 | *pos++ = 0x0; | 2419 | *pos++ = 0x0; |
2422 | 2420 | ||
2423 | if (ieee80211_add_srates_ie(&sdata->vif, skb, true) || | 2421 | if (ieee80211_add_srates_ie(sdata, skb, true) || |
2424 | mesh_add_ds_params_ie(skb, sdata) || | 2422 | mesh_add_ds_params_ie(skb, sdata) || |
2425 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) || | 2423 | ieee80211_add_ext_srates_ie(sdata, skb, true) || |
2426 | mesh_add_rsn_ie(skb, sdata) || | 2424 | mesh_add_rsn_ie(skb, sdata) || |
2427 | mesh_add_ht_cap_ie(skb, sdata) || | 2425 | mesh_add_ht_cap_ie(skb, sdata) || |
2428 | mesh_add_ht_oper_ie(skb, sdata) || | 2426 | mesh_add_ht_oper_ie(skb, sdata) || |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 242ecde381f6..64493a7bef1a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -268,6 +268,10 @@ EXPORT_SYMBOL(ieee80211_ctstoself_duration); | |||
268 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) | 268 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) |
269 | { | 269 | { |
270 | struct ieee80211_sub_if_data *sdata; | 270 | struct ieee80211_sub_if_data *sdata; |
271 | int n_acs = IEEE80211_NUM_ACS; | ||
272 | |||
273 | if (local->hw.queues < IEEE80211_NUM_ACS) | ||
274 | n_acs = 1; | ||
271 | 275 | ||
272 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 276 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
273 | int ac; | 277 | int ac; |
@@ -279,7 +283,7 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) | |||
279 | local->queue_stop_reasons[sdata->vif.cab_queue] != 0) | 283 | local->queue_stop_reasons[sdata->vif.cab_queue] != 0) |
280 | continue; | 284 | continue; |
281 | 285 | ||
282 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 286 | for (ac = 0; ac < n_acs; ac++) { |
283 | int ac_queue = sdata->vif.hw_queue[ac]; | 287 | int ac_queue = sdata->vif.hw_queue[ac]; |
284 | 288 | ||
285 | if (ac_queue == queue || | 289 | if (ac_queue == queue || |
@@ -341,6 +345,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
341 | { | 345 | { |
342 | struct ieee80211_local *local = hw_to_local(hw); | 346 | struct ieee80211_local *local = hw_to_local(hw); |
343 | struct ieee80211_sub_if_data *sdata; | 347 | struct ieee80211_sub_if_data *sdata; |
348 | int n_acs = IEEE80211_NUM_ACS; | ||
344 | 349 | ||
345 | trace_stop_queue(local, queue, reason); | 350 | trace_stop_queue(local, queue, reason); |
346 | 351 | ||
@@ -352,11 +357,14 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
352 | 357 | ||
353 | __set_bit(reason, &local->queue_stop_reasons[queue]); | 358 | __set_bit(reason, &local->queue_stop_reasons[queue]); |
354 | 359 | ||
360 | if (local->hw.queues < IEEE80211_NUM_ACS) | ||
361 | n_acs = 1; | ||
362 | |||
355 | rcu_read_lock(); | 363 | rcu_read_lock(); |
356 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 364 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
357 | int ac; | 365 | int ac; |
358 | 366 | ||
359 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 367 | for (ac = 0; ac < n_acs; ac++) { |
360 | if (sdata->vif.hw_queue[ac] == queue || | 368 | if (sdata->vif.hw_queue[ac] == queue || |
361 | sdata->vif.cab_queue == queue) | 369 | sdata->vif.cab_queue == queue) |
362 | netif_stop_subqueue(sdata->dev, ac); | 370 | netif_stop_subqueue(sdata->dev, ac); |
@@ -1072,6 +1080,10 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1072 | pos += noffset - offset; | 1080 | pos += noffset - offset; |
1073 | } | 1081 | } |
1074 | 1082 | ||
1083 | if (sband->vht_cap.vht_supported) | ||
1084 | pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, | ||
1085 | sband->vht_cap.cap); | ||
1086 | |||
1075 | return pos - buffer; | 1087 | return pos - buffer; |
1076 | } | 1088 | } |
1077 | 1089 | ||
@@ -1411,10 +1423,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1411 | if (ieee80211_sdata_running(sdata)) | 1423 | if (ieee80211_sdata_running(sdata)) |
1412 | ieee80211_enable_keys(sdata); | 1424 | ieee80211_enable_keys(sdata); |
1413 | 1425 | ||
1426 | wake_up: | ||
1414 | local->in_reconfig = false; | 1427 | local->in_reconfig = false; |
1415 | barrier(); | 1428 | barrier(); |
1416 | 1429 | ||
1417 | wake_up: | ||
1418 | /* | 1430 | /* |
1419 | * Clear the WLAN_STA_BLOCK_BA flag so new aggregation | 1431 | * Clear the WLAN_STA_BLOCK_BA flag so new aggregation |
1420 | * sessions can be established after a resume. | 1432 | * sessions can be established after a resume. |
@@ -1699,6 +1711,27 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
1699 | return pos; | 1711 | return pos; |
1700 | } | 1712 | } |
1701 | 1713 | ||
1714 | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | ||
1715 | u32 cap) | ||
1716 | { | ||
1717 | __le32 tmp; | ||
1718 | |||
1719 | *pos++ = WLAN_EID_VHT_CAPABILITY; | ||
1720 | *pos++ = sizeof(struct ieee80211_vht_capabilities); | ||
1721 | memset(pos, 0, sizeof(struct ieee80211_vht_capabilities)); | ||
1722 | |||
1723 | /* capability flags */ | ||
1724 | tmp = cpu_to_le32(cap); | ||
1725 | memcpy(pos, &tmp, sizeof(u32)); | ||
1726 | pos += sizeof(u32); | ||
1727 | |||
1728 | /* VHT MCS set */ | ||
1729 | memcpy(pos, &vht_cap->vht_mcs, sizeof(vht_cap->vht_mcs)); | ||
1730 | pos += sizeof(vht_cap->vht_mcs); | ||
1731 | |||
1732 | return pos; | ||
1733 | } | ||
1734 | |||
1702 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 1735 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
1703 | struct ieee80211_channel *channel, | 1736 | struct ieee80211_channel *channel, |
1704 | enum nl80211_channel_type channel_type, | 1737 | enum nl80211_channel_type channel_type, |
@@ -1764,15 +1797,14 @@ ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper) | |||
1764 | return channel_type; | 1797 | return channel_type; |
1765 | } | 1798 | } |
1766 | 1799 | ||
1767 | int ieee80211_add_srates_ie(struct ieee80211_vif *vif, | 1800 | int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, |
1768 | struct sk_buff *skb, bool need_basic) | 1801 | struct sk_buff *skb, bool need_basic) |
1769 | { | 1802 | { |
1770 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
1771 | struct ieee80211_local *local = sdata->local; | 1803 | struct ieee80211_local *local = sdata->local; |
1772 | struct ieee80211_supported_band *sband; | 1804 | struct ieee80211_supported_band *sband; |
1773 | int rate; | 1805 | int rate; |
1774 | u8 i, rates, *pos; | 1806 | u8 i, rates, *pos; |
1775 | u32 basic_rates = vif->bss_conf.basic_rates; | 1807 | u32 basic_rates = sdata->vif.bss_conf.basic_rates; |
1776 | 1808 | ||
1777 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1809 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1778 | rates = sband->n_bitrates; | 1810 | rates = sband->n_bitrates; |
@@ -1796,15 +1828,14 @@ int ieee80211_add_srates_ie(struct ieee80211_vif *vif, | |||
1796 | return 0; | 1828 | return 0; |
1797 | } | 1829 | } |
1798 | 1830 | ||
1799 | int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, | 1831 | int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, |
1800 | struct sk_buff *skb, bool need_basic) | 1832 | struct sk_buff *skb, bool need_basic) |
1801 | { | 1833 | { |
1802 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
1803 | struct ieee80211_local *local = sdata->local; | 1834 | struct ieee80211_local *local = sdata->local; |
1804 | struct ieee80211_supported_band *sband; | 1835 | struct ieee80211_supported_band *sband; |
1805 | int rate; | 1836 | int rate; |
1806 | u8 i, exrates, *pos; | 1837 | u8 i, exrates, *pos; |
1807 | u32 basic_rates = vif->bss_conf.basic_rates; | 1838 | u32 basic_rates = sdata->vif.bss_conf.basic_rates; |
1808 | 1839 | ||
1809 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1840 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1810 | exrates = sband->n_bitrates; | 1841 | exrates = sband->n_bitrates; |
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 55a28ab21db9..0f7e0d621ab0 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o | |||
10 | obj-$(CONFIG_WEXT_PRIV) += wext-priv.o | 10 | obj-$(CONFIG_WEXT_PRIV) += wext-priv.o |
11 | 11 | ||
12 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o | 12 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o |
13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o | 13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o |
14 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o | 14 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o |
15 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o | 15 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o |
16 | cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o | 16 | cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o |
diff --git a/net/wireless/ap.c b/net/wireless/ap.c new file mode 100644 index 000000000000..fcc60d8dbefa --- /dev/null +++ b/net/wireless/ap.c | |||
@@ -0,0 +1,46 @@ | |||
1 | #include <linux/ieee80211.h> | ||
2 | #include <linux/export.h> | ||
3 | #include <net/cfg80211.h> | ||
4 | #include "nl80211.h" | ||
5 | #include "core.h" | ||
6 | |||
7 | |||
8 | static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||
9 | struct net_device *dev) | ||
10 | { | ||
11 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
12 | int err; | ||
13 | |||
14 | ASSERT_WDEV_LOCK(wdev); | ||
15 | |||
16 | if (!rdev->ops->stop_ap) | ||
17 | return -EOPNOTSUPP; | ||
18 | |||
19 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
20 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
21 | return -EOPNOTSUPP; | ||
22 | |||
23 | if (!wdev->beacon_interval) | ||
24 | return -ENOENT; | ||
25 | |||
26 | err = rdev->ops->stop_ap(&rdev->wiphy, dev); | ||
27 | if (!err) { | ||
28 | wdev->beacon_interval = 0; | ||
29 | wdev->channel = NULL; | ||
30 | } | ||
31 | |||
32 | return err; | ||
33 | } | ||
34 | |||
35 | int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||
36 | struct net_device *dev) | ||
37 | { | ||
38 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
39 | int err; | ||
40 | |||
41 | wdev_lock(wdev); | ||
42 | err = __cfg80211_stop_ap(rdev, dev); | ||
43 | wdev_unlock(wdev); | ||
44 | |||
45 | return err; | ||
46 | } | ||
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index c1999e45a07c..434c56b92c3c 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -82,13 +82,73 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, | |||
82 | int freq, enum nl80211_channel_type chantype) | 82 | int freq, enum nl80211_channel_type chantype) |
83 | { | 83 | { |
84 | struct ieee80211_channel *chan; | 84 | struct ieee80211_channel *chan; |
85 | int err; | ||
85 | 86 | ||
86 | if (!rdev->ops->set_monitor_channel) | 87 | if (!rdev->ops->set_monitor_channel) |
87 | return -EOPNOTSUPP; | 88 | return -EOPNOTSUPP; |
89 | if (!cfg80211_has_monitors_only(rdev)) | ||
90 | return -EBUSY; | ||
88 | 91 | ||
89 | chan = rdev_freq_to_chan(rdev, freq, chantype); | 92 | chan = rdev_freq_to_chan(rdev, freq, chantype); |
90 | if (!chan) | 93 | if (!chan) |
91 | return -EINVAL; | 94 | return -EINVAL; |
92 | 95 | ||
93 | return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype); | 96 | err = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype); |
97 | if (!err) { | ||
98 | rdev->monitor_channel = chan; | ||
99 | rdev->monitor_channel_type = chantype; | ||
100 | } | ||
101 | |||
102 | return err; | ||
103 | } | ||
104 | |||
105 | void | ||
106 | cfg80211_get_chan_state(struct cfg80211_registered_device *rdev, | ||
107 | struct wireless_dev *wdev, | ||
108 | struct ieee80211_channel **chan, | ||
109 | enum cfg80211_chan_mode *chanmode) | ||
110 | { | ||
111 | *chan = NULL; | ||
112 | *chanmode = CHAN_MODE_UNDEFINED; | ||
113 | |||
114 | ASSERT_RDEV_LOCK(rdev); | ||
115 | ASSERT_WDEV_LOCK(wdev); | ||
116 | |||
117 | if (!netif_running(wdev->netdev)) | ||
118 | return; | ||
119 | |||
120 | switch (wdev->iftype) { | ||
121 | case NL80211_IFTYPE_ADHOC: | ||
122 | if (wdev->current_bss) { | ||
123 | *chan = wdev->current_bss->pub.channel; | ||
124 | *chanmode = wdev->ibss_fixed | ||
125 | ? CHAN_MODE_SHARED | ||
126 | : CHAN_MODE_EXCLUSIVE; | ||
127 | return; | ||
128 | } | ||
129 | case NL80211_IFTYPE_STATION: | ||
130 | case NL80211_IFTYPE_P2P_CLIENT: | ||
131 | if (wdev->current_bss) { | ||
132 | *chan = wdev->current_bss->pub.channel; | ||
133 | *chanmode = CHAN_MODE_SHARED; | ||
134 | return; | ||
135 | } | ||
136 | break; | ||
137 | case NL80211_IFTYPE_AP: | ||
138 | case NL80211_IFTYPE_P2P_GO: | ||
139 | case NL80211_IFTYPE_MESH_POINT: | ||
140 | *chan = wdev->channel; | ||
141 | *chanmode = CHAN_MODE_SHARED; | ||
142 | return; | ||
143 | case NL80211_IFTYPE_MONITOR: | ||
144 | case NL80211_IFTYPE_AP_VLAN: | ||
145 | case NL80211_IFTYPE_WDS: | ||
146 | /* these interface types don't really have a channel */ | ||
147 | return; | ||
148 | case NL80211_IFTYPE_UNSPECIFIED: | ||
149 | case NUM_NL80211_IFTYPES: | ||
150 | WARN_ON(1); | ||
151 | } | ||
152 | |||
153 | return; | ||
94 | } | 154 | } |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 907f62c80e28..eb60410ae588 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -373,6 +373,14 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) | |||
373 | if (WARN_ON(!c->num_different_channels)) | 373 | if (WARN_ON(!c->num_different_channels)) |
374 | return -EINVAL; | 374 | return -EINVAL; |
375 | 375 | ||
376 | /* | ||
377 | * Put a sane limit on maximum number of different | ||
378 | * channels to simplify channel accounting code. | ||
379 | */ | ||
380 | if (WARN_ON(c->num_different_channels > | ||
381 | CFG80211_MAX_NUM_DIFFERENT_CHANNELS)) | ||
382 | return -EINVAL; | ||
383 | |||
376 | if (WARN_ON(!c->n_limits)) | 384 | if (WARN_ON(!c->n_limits)) |
377 | return -EINVAL; | 385 | return -EINVAL; |
378 | 386 | ||
@@ -421,9 +429,11 @@ int wiphy_register(struct wiphy *wiphy) | |||
421 | int i; | 429 | int i; |
422 | u16 ifmodes = wiphy->interface_modes; | 430 | u16 ifmodes = wiphy->interface_modes; |
423 | 431 | ||
432 | #ifdef CONFIG_PM | ||
424 | if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && | 433 | if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && |
425 | !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) | 434 | !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) |
426 | return -EINVAL; | 435 | return -EINVAL; |
436 | #endif | ||
427 | 437 | ||
428 | if (WARN_ON(wiphy->ap_sme_capa && | 438 | if (WARN_ON(wiphy->ap_sme_capa && |
429 | !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) | 439 | !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) |
@@ -458,8 +468,14 @@ int wiphy_register(struct wiphy *wiphy) | |||
458 | continue; | 468 | continue; |
459 | 469 | ||
460 | sband->band = band; | 470 | sband->band = band; |
461 | 471 | if (WARN_ON(!sband->n_channels)) | |
462 | if (WARN_ON(!sband->n_channels || !sband->n_bitrates)) | 472 | return -EINVAL; |
473 | /* | ||
474 | * on 60gHz band, there are no legacy rates, so | ||
475 | * n_bitrates is 0 | ||
476 | */ | ||
477 | if (WARN_ON(band != IEEE80211_BAND_60GHZ && | ||
478 | !sband->n_bitrates)) | ||
463 | return -EINVAL; | 479 | return -EINVAL; |
464 | 480 | ||
465 | /* | 481 | /* |
@@ -500,12 +516,14 @@ int wiphy_register(struct wiphy *wiphy) | |||
500 | return -EINVAL; | 516 | return -EINVAL; |
501 | } | 517 | } |
502 | 518 | ||
519 | #ifdef CONFIG_PM | ||
503 | if (rdev->wiphy.wowlan.n_patterns) { | 520 | if (rdev->wiphy.wowlan.n_patterns) { |
504 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || | 521 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || |
505 | rdev->wiphy.wowlan.pattern_min_len > | 522 | rdev->wiphy.wowlan.pattern_min_len > |
506 | rdev->wiphy.wowlan.pattern_max_len)) | 523 | rdev->wiphy.wowlan.pattern_max_len)) |
507 | return -EINVAL; | 524 | return -EINVAL; |
508 | } | 525 | } |
526 | #endif | ||
509 | 527 | ||
510 | /* check and set up bitrates */ | 528 | /* check and set up bitrates */ |
511 | ieee80211_set_bitrate_flags(wiphy); | 529 | ieee80211_set_bitrate_flags(wiphy); |
@@ -713,6 +731,61 @@ static struct device_type wiphy_type = { | |||
713 | .name = "wlan", | 731 | .name = "wlan", |
714 | }; | 732 | }; |
715 | 733 | ||
734 | static struct ieee80211_channel * | ||
735 | cfg80211_get_any_chan(struct cfg80211_registered_device *rdev) | ||
736 | { | ||
737 | struct ieee80211_supported_band *sband; | ||
738 | int i; | ||
739 | |||
740 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | ||
741 | sband = rdev->wiphy.bands[i]; | ||
742 | if (sband && sband->n_channels > 0) | ||
743 | return &sband->channels[0]; | ||
744 | } | ||
745 | |||
746 | return NULL; | ||
747 | } | ||
748 | |||
749 | static void cfg80211_init_mon_chan(struct cfg80211_registered_device *rdev) | ||
750 | { | ||
751 | struct ieee80211_channel *chan; | ||
752 | |||
753 | chan = cfg80211_get_any_chan(rdev); | ||
754 | if (WARN_ON(!chan)) | ||
755 | return; | ||
756 | |||
757 | mutex_lock(&rdev->devlist_mtx); | ||
758 | WARN_ON(cfg80211_set_monitor_channel(rdev, chan->center_freq, | ||
759 | NL80211_CHAN_NO_HT)); | ||
760 | mutex_unlock(&rdev->devlist_mtx); | ||
761 | } | ||
762 | |||
763 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | ||
764 | enum nl80211_iftype iftype, int num) | ||
765 | { | ||
766 | bool has_monitors_only_old = cfg80211_has_monitors_only(rdev); | ||
767 | bool has_monitors_only_new; | ||
768 | |||
769 | ASSERT_RTNL(); | ||
770 | |||
771 | rdev->num_running_ifaces += num; | ||
772 | if (iftype == NL80211_IFTYPE_MONITOR) | ||
773 | rdev->num_running_monitor_ifaces += num; | ||
774 | |||
775 | has_monitors_only_new = cfg80211_has_monitors_only(rdev); | ||
776 | if (has_monitors_only_new != has_monitors_only_old) { | ||
777 | rdev->ops->set_monitor_enabled(&rdev->wiphy, | ||
778 | has_monitors_only_new); | ||
779 | |||
780 | if (!has_monitors_only_new) { | ||
781 | rdev->monitor_channel = NULL; | ||
782 | rdev->monitor_channel_type = NL80211_CHAN_NO_HT; | ||
783 | } else { | ||
784 | cfg80211_init_mon_chan(rdev); | ||
785 | } | ||
786 | } | ||
787 | } | ||
788 | |||
716 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | 789 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, |
717 | unsigned long state, | 790 | unsigned long state, |
718 | void *ndev) | 791 | void *ndev) |
@@ -806,12 +879,16 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
806 | case NL80211_IFTYPE_MESH_POINT: | 879 | case NL80211_IFTYPE_MESH_POINT: |
807 | cfg80211_leave_mesh(rdev, dev); | 880 | cfg80211_leave_mesh(rdev, dev); |
808 | break; | 881 | break; |
882 | case NL80211_IFTYPE_AP: | ||
883 | cfg80211_stop_ap(rdev, dev); | ||
884 | break; | ||
809 | default: | 885 | default: |
810 | break; | 886 | break; |
811 | } | 887 | } |
812 | wdev->beacon_interval = 0; | 888 | wdev->beacon_interval = 0; |
813 | break; | 889 | break; |
814 | case NETDEV_DOWN: | 890 | case NETDEV_DOWN: |
891 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); | ||
815 | dev_hold(dev); | 892 | dev_hold(dev); |
816 | queue_work(cfg80211_wq, &wdev->cleanup_work); | 893 | queue_work(cfg80211_wq, &wdev->cleanup_work); |
817 | break; | 894 | break; |
@@ -917,9 +994,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
917 | return notifier_from_errno(-EOPNOTSUPP); | 994 | return notifier_from_errno(-EOPNOTSUPP); |
918 | if (rfkill_blocked(rdev->rfkill)) | 995 | if (rfkill_blocked(rdev->rfkill)) |
919 | return notifier_from_errno(-ERFKILL); | 996 | return notifier_from_errno(-ERFKILL); |
997 | mutex_lock(&rdev->devlist_mtx); | ||
920 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); | 998 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); |
999 | mutex_unlock(&rdev->devlist_mtx); | ||
921 | if (ret) | 1000 | if (ret) |
922 | return notifier_from_errno(ret); | 1001 | return notifier_from_errno(ret); |
1002 | cfg80211_update_iface_num(rdev, wdev->iftype, 1); | ||
923 | break; | 1003 | break; |
924 | } | 1004 | } |
925 | 1005 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index 609a579255ac..377dc394f48c 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/debugfs.h> | 13 | #include <linux/debugfs.h> |
14 | #include <linux/rfkill.h> | 14 | #include <linux/rfkill.h> |
15 | #include <linux/workqueue.h> | 15 | #include <linux/workqueue.h> |
16 | #include <linux/rtnetlink.h> | ||
16 | #include <net/genetlink.h> | 17 | #include <net/genetlink.h> |
17 | #include <net/cfg80211.h> | 18 | #include <net/cfg80211.h> |
18 | #include "reg.h" | 19 | #include "reg.h" |
@@ -56,6 +57,13 @@ struct cfg80211_registered_device { | |||
56 | 57 | ||
57 | u32 ap_beacons_nlpid; | 58 | u32 ap_beacons_nlpid; |
58 | 59 | ||
60 | /* protected by RTNL only */ | ||
61 | int num_running_ifaces; | ||
62 | int num_running_monitor_ifaces; | ||
63 | |||
64 | struct ieee80211_channel *monitor_channel; | ||
65 | enum nl80211_channel_type monitor_channel_type; | ||
66 | |||
59 | /* BSSes/scanning */ | 67 | /* BSSes/scanning */ |
60 | spinlock_t bss_lock; | 68 | spinlock_t bss_lock; |
61 | struct list_head bss_list; | 69 | struct list_head bss_list; |
@@ -197,6 +205,14 @@ static inline void wdev_unlock(struct wireless_dev *wdev) | |||
197 | #define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) | 205 | #define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) |
198 | #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) | 206 | #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) |
199 | 207 | ||
208 | static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev) | ||
209 | { | ||
210 | ASSERT_RTNL(); | ||
211 | |||
212 | return rdev->num_running_ifaces == rdev->num_running_monitor_ifaces && | ||
213 | rdev->num_running_ifaces > 0; | ||
214 | } | ||
215 | |||
200 | enum cfg80211_event_type { | 216 | enum cfg80211_event_type { |
201 | EVENT_CONNECT_RESULT, | 217 | EVENT_CONNECT_RESULT, |
202 | EVENT_ROAMED, | 218 | EVENT_ROAMED, |
@@ -241,6 +257,12 @@ struct cfg80211_cached_keys { | |||
241 | int def, defmgmt; | 257 | int def, defmgmt; |
242 | }; | 258 | }; |
243 | 259 | ||
260 | enum cfg80211_chan_mode { | ||
261 | CHAN_MODE_UNDEFINED, | ||
262 | CHAN_MODE_SHARED, | ||
263 | CHAN_MODE_EXCLUSIVE, | ||
264 | }; | ||
265 | |||
244 | 266 | ||
245 | /* free object */ | 267 | /* free object */ |
246 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); | 268 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); |
@@ -289,6 +311,10 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | |||
289 | struct wireless_dev *wdev, int freq, | 311 | struct wireless_dev *wdev, int freq, |
290 | enum nl80211_channel_type channel_type); | 312 | enum nl80211_channel_type channel_type); |
291 | 313 | ||
314 | /* AP */ | ||
315 | int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||
316 | struct net_device *dev); | ||
317 | |||
292 | /* MLME */ | 318 | /* MLME */ |
293 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | 319 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, |
294 | struct net_device *dev, | 320 | struct net_device *dev, |
@@ -404,9 +430,20 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
404 | u32 *flags, struct vif_params *params); | 430 | u32 *flags, struct vif_params *params); |
405 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); | 431 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); |
406 | 432 | ||
407 | int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | 433 | int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, |
408 | struct wireless_dev *wdev, | 434 | struct wireless_dev *wdev, |
409 | enum nl80211_iftype iftype); | 435 | enum nl80211_iftype iftype, |
436 | struct ieee80211_channel *chan, | ||
437 | enum cfg80211_chan_mode chanmode); | ||
438 | |||
439 | static inline int | ||
440 | cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | ||
441 | struct wireless_dev *wdev, | ||
442 | enum nl80211_iftype iftype) | ||
443 | { | ||
444 | return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL, | ||
445 | CHAN_MODE_UNDEFINED); | ||
446 | } | ||
410 | 447 | ||
411 | static inline int | 448 | static inline int |
412 | cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, | 449 | cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, |
@@ -415,6 +452,22 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, | |||
415 | return cfg80211_can_change_interface(rdev, NULL, iftype); | 452 | return cfg80211_can_change_interface(rdev, NULL, iftype); |
416 | } | 453 | } |
417 | 454 | ||
455 | static inline int | ||
456 | cfg80211_can_use_chan(struct cfg80211_registered_device *rdev, | ||
457 | struct wireless_dev *wdev, | ||
458 | struct ieee80211_channel *chan, | ||
459 | enum cfg80211_chan_mode chanmode) | ||
460 | { | ||
461 | return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | ||
462 | chan, chanmode); | ||
463 | } | ||
464 | |||
465 | void | ||
466 | cfg80211_get_chan_state(struct cfg80211_registered_device *rdev, | ||
467 | struct wireless_dev *wdev, | ||
468 | struct ieee80211_channel **chan, | ||
469 | enum cfg80211_chan_mode *chanmode); | ||
470 | |||
418 | struct ieee80211_channel * | 471 | struct ieee80211_channel * |
419 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, | 472 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, |
420 | int freq, enum nl80211_channel_type channel_type); | 473 | int freq, enum nl80211_channel_type channel_type); |
@@ -428,6 +481,11 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, | |||
428 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | 481 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, |
429 | u32 beacon_int); | 482 | u32 beacon_int); |
430 | 483 | ||
484 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | ||
485 | enum nl80211_iftype iftype, int num); | ||
486 | |||
487 | #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 | ||
488 | |||
431 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS | 489 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS |
432 | #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) | 490 | #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) |
433 | #else | 491 | #else |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 89baa3328411..ca5672f6ee2f 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -113,10 +113,21 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
113 | kfree(wdev->connect_keys); | 113 | kfree(wdev->connect_keys); |
114 | wdev->connect_keys = connkeys; | 114 | wdev->connect_keys = connkeys; |
115 | 115 | ||
116 | wdev->ibss_fixed = params->channel_fixed; | ||
116 | #ifdef CONFIG_CFG80211_WEXT | 117 | #ifdef CONFIG_CFG80211_WEXT |
117 | wdev->wext.ibss.channel = params->channel; | 118 | wdev->wext.ibss.channel = params->channel; |
118 | #endif | 119 | #endif |
119 | wdev->sme_state = CFG80211_SME_CONNECTING; | 120 | wdev->sme_state = CFG80211_SME_CONNECTING; |
121 | |||
122 | err = cfg80211_can_use_chan(rdev, wdev, params->channel, | ||
123 | params->channel_fixed | ||
124 | ? CHAN_MODE_SHARED | ||
125 | : CHAN_MODE_EXCLUSIVE); | ||
126 | if (err) { | ||
127 | wdev->connect_keys = NULL; | ||
128 | return err; | ||
129 | } | ||
130 | |||
120 | err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); | 131 | err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); |
121 | if (err) { | 132 | if (err) { |
122 | wdev->connect_keys = NULL; | 133 | wdev->connect_keys = NULL; |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 3b73b07486cf..c384e77ff77a 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
@@ -155,10 +155,16 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
155 | setup->channel_type)) | 155 | setup->channel_type)) |
156 | return -EINVAL; | 156 | return -EINVAL; |
157 | 157 | ||
158 | err = cfg80211_can_use_chan(rdev, wdev, setup->channel, | ||
159 | CHAN_MODE_SHARED); | ||
160 | if (err) | ||
161 | return err; | ||
162 | |||
158 | err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); | 163 | err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); |
159 | if (!err) { | 164 | if (!err) { |
160 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); | 165 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); |
161 | wdev->mesh_id_len = setup->mesh_id_len; | 166 | wdev->mesh_id_len = setup->mesh_id_len; |
167 | wdev->channel = setup->channel; | ||
162 | } | 168 | } |
163 | 169 | ||
164 | return err; | 170 | return err; |
@@ -172,9 +178,11 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
172 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 178 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
173 | int err; | 179 | int err; |
174 | 180 | ||
181 | mutex_lock(&rdev->devlist_mtx); | ||
175 | wdev_lock(wdev); | 182 | wdev_lock(wdev); |
176 | err = __cfg80211_join_mesh(rdev, dev, setup, conf); | 183 | err = __cfg80211_join_mesh(rdev, dev, setup, conf); |
177 | wdev_unlock(wdev); | 184 | wdev_unlock(wdev); |
185 | mutex_unlock(&rdev->devlist_mtx); | ||
178 | 186 | ||
179 | return err; | 187 | return err; |
180 | } | 188 | } |
@@ -184,6 +192,7 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | |||
184 | enum nl80211_channel_type channel_type) | 192 | enum nl80211_channel_type channel_type) |
185 | { | 193 | { |
186 | struct ieee80211_channel *channel; | 194 | struct ieee80211_channel *channel; |
195 | int err; | ||
187 | 196 | ||
188 | channel = rdev_freq_to_chan(rdev, freq, channel_type); | 197 | channel = rdev_freq_to_chan(rdev, freq, channel_type); |
189 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, | 198 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, |
@@ -205,9 +214,19 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | |||
205 | 214 | ||
206 | if (!netif_running(wdev->netdev)) | 215 | if (!netif_running(wdev->netdev)) |
207 | return -ENETDOWN; | 216 | return -ENETDOWN; |
208 | return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, | 217 | |
209 | wdev->netdev, | 218 | err = cfg80211_can_use_chan(rdev, wdev, channel, |
210 | channel); | 219 | CHAN_MODE_SHARED); |
220 | if (err) | ||
221 | return err; | ||
222 | |||
223 | err = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, | ||
224 | wdev->netdev, | ||
225 | channel); | ||
226 | if (!err) | ||
227 | wdev->channel = channel; | ||
228 | |||
229 | return err; | ||
211 | } | 230 | } |
212 | 231 | ||
213 | if (wdev->mesh_id_len) | 232 | if (wdev->mesh_id_len) |
@@ -249,8 +268,11 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | |||
249 | return -ENOTCONN; | 268 | return -ENOTCONN; |
250 | 269 | ||
251 | err = rdev->ops->leave_mesh(&rdev->wiphy, dev); | 270 | err = rdev->ops->leave_mesh(&rdev->wiphy, dev); |
252 | if (!err) | 271 | if (!err) { |
253 | wdev->mesh_id_len = 0; | 272 | wdev->mesh_id_len = 0; |
273 | wdev->channel = NULL; | ||
274 | } | ||
275 | |||
254 | return err; | 276 | return err; |
255 | } | 277 | } |
256 | 278 | ||
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index da4406f11929..d4fece3bb18a 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -302,8 +302,14 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
302 | if (!req.bss) | 302 | if (!req.bss) |
303 | return -ENOENT; | 303 | return -ENOENT; |
304 | 304 | ||
305 | err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel, | ||
306 | CHAN_MODE_SHARED); | ||
307 | if (err) | ||
308 | goto out; | ||
309 | |||
305 | err = rdev->ops->auth(&rdev->wiphy, dev, &req); | 310 | err = rdev->ops->auth(&rdev->wiphy, dev, &req); |
306 | 311 | ||
312 | out: | ||
307 | cfg80211_put_bss(req.bss); | 313 | cfg80211_put_bss(req.bss); |
308 | return err; | 314 | return err; |
309 | } | 315 | } |
@@ -317,11 +323,13 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
317 | { | 323 | { |
318 | int err; | 324 | int err; |
319 | 325 | ||
326 | mutex_lock(&rdev->devlist_mtx); | ||
320 | wdev_lock(dev->ieee80211_ptr); | 327 | wdev_lock(dev->ieee80211_ptr); |
321 | err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, | 328 | err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, |
322 | ssid, ssid_len, ie, ie_len, | 329 | ssid, ssid_len, ie, ie_len, |
323 | key, key_len, key_idx); | 330 | key, key_len, key_idx); |
324 | wdev_unlock(dev->ieee80211_ptr); | 331 | wdev_unlock(dev->ieee80211_ptr); |
332 | mutex_unlock(&rdev->devlist_mtx); | ||
325 | 333 | ||
326 | return err; | 334 | return err; |
327 | } | 335 | } |
@@ -397,8 +405,14 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
397 | return -ENOENT; | 405 | return -ENOENT; |
398 | } | 406 | } |
399 | 407 | ||
408 | err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel, | ||
409 | CHAN_MODE_SHARED); | ||
410 | if (err) | ||
411 | goto out; | ||
412 | |||
400 | err = rdev->ops->assoc(&rdev->wiphy, dev, &req); | 413 | err = rdev->ops->assoc(&rdev->wiphy, dev, &req); |
401 | 414 | ||
415 | out: | ||
402 | if (err) { | 416 | if (err) { |
403 | if (was_connected) | 417 | if (was_connected) |
404 | wdev->sme_state = CFG80211_SME_CONNECTED; | 418 | wdev->sme_state = CFG80211_SME_CONNECTED; |
@@ -421,11 +435,13 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
421 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 435 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
422 | int err; | 436 | int err; |
423 | 437 | ||
438 | mutex_lock(&rdev->devlist_mtx); | ||
424 | wdev_lock(wdev); | 439 | wdev_lock(wdev); |
425 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 440 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, |
426 | ssid, ssid_len, ie, ie_len, use_mfp, crypt, | 441 | ssid, ssid_len, ie, ie_len, use_mfp, crypt, |
427 | assoc_flags, ht_capa, ht_capa_mask); | 442 | assoc_flags, ht_capa, ht_capa_mask); |
428 | wdev_unlock(wdev); | 443 | wdev_unlock(wdev); |
444 | mutex_unlock(&rdev->devlist_mtx); | ||
429 | 445 | ||
430 | return err; | 446 | return err; |
431 | } | 447 | } |
@@ -947,6 +963,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq, | |||
947 | if (WARN_ON(!chan)) | 963 | if (WARN_ON(!chan)) |
948 | goto out; | 964 | goto out; |
949 | 965 | ||
966 | wdev->channel = chan; | ||
950 | nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL); | 967 | nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL); |
951 | out: | 968 | out: |
952 | wdev_unlock(wdev); | 969 | wdev_unlock(wdev); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 234ff3bbd104..2a5cdb60bc6e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -921,6 +921,15 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
921 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) | 921 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) |
922 | goto nla_put_failure; | 922 | goto nla_put_failure; |
923 | 923 | ||
924 | /* add VHT info */ | ||
925 | if (dev->wiphy.bands[band]->vht_cap.vht_supported && | ||
926 | (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET, | ||
927 | sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs), | ||
928 | &dev->wiphy.bands[band]->vht_cap.vht_mcs) || | ||
929 | nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA, | ||
930 | dev->wiphy.bands[band]->vht_cap.cap))) | ||
931 | goto nla_put_failure; | ||
932 | |||
924 | /* add frequencies */ | 933 | /* add frequencies */ |
925 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); | 934 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); |
926 | if (!nl_freqs) | 935 | if (!nl_freqs) |
@@ -1112,6 +1121,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1112 | nla_nest_end(msg, nl_ifs); | 1121 | nla_nest_end(msg, nl_ifs); |
1113 | } | 1122 | } |
1114 | 1123 | ||
1124 | #ifdef CONFIG_PM | ||
1115 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { | 1125 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { |
1116 | struct nlattr *nl_wowlan; | 1126 | struct nlattr *nl_wowlan; |
1117 | 1127 | ||
@@ -1152,6 +1162,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1152 | 1162 | ||
1153 | nla_nest_end(msg, nl_wowlan); | 1163 | nla_nest_end(msg, nl_wowlan); |
1154 | } | 1164 | } |
1165 | #endif | ||
1155 | 1166 | ||
1156 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | 1167 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, |
1157 | dev->wiphy.software_iftypes)) | 1168 | dev->wiphy.software_iftypes)) |
@@ -1678,16 +1689,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1678 | (cfg80211_rdev_list_generation << 2))) | 1689 | (cfg80211_rdev_list_generation << 2))) |
1679 | goto nla_put_failure; | 1690 | goto nla_put_failure; |
1680 | 1691 | ||
1681 | if (rdev->ops->get_channel) { | 1692 | if (rdev->monitor_channel) { |
1682 | struct ieee80211_channel *chan; | 1693 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, |
1683 | enum nl80211_channel_type channel_type; | 1694 | rdev->monitor_channel->center_freq) || |
1684 | 1695 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, | |
1685 | chan = rdev->ops->get_channel(&rdev->wiphy, &channel_type); | 1696 | rdev->monitor_channel_type)) |
1686 | if (chan && | ||
1687 | (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, | ||
1688 | chan->center_freq) || | ||
1689 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, | ||
1690 | channel_type))) | ||
1691 | goto nla_put_failure; | 1697 | goto nla_put_failure; |
1692 | } | 1698 | } |
1693 | 1699 | ||
@@ -2472,11 +2478,20 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
2472 | params.channel_type)) | 2478 | params.channel_type)) |
2473 | return -EINVAL; | 2479 | return -EINVAL; |
2474 | 2480 | ||
2481 | mutex_lock(&rdev->devlist_mtx); | ||
2482 | err = cfg80211_can_use_chan(rdev, wdev, params.channel, | ||
2483 | CHAN_MODE_SHARED); | ||
2484 | mutex_unlock(&rdev->devlist_mtx); | ||
2485 | |||
2486 | if (err) | ||
2487 | return err; | ||
2488 | |||
2475 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); | 2489 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); |
2476 | if (!err) { | 2490 | if (!err) { |
2477 | wdev->preset_chan = params.channel; | 2491 | wdev->preset_chan = params.channel; |
2478 | wdev->preset_chantype = params.channel_type; | 2492 | wdev->preset_chantype = params.channel_type; |
2479 | wdev->beacon_interval = params.beacon_interval; | 2493 | wdev->beacon_interval = params.beacon_interval; |
2494 | wdev->channel = params.channel; | ||
2480 | } | 2495 | } |
2481 | return err; | 2496 | return err; |
2482 | } | 2497 | } |
@@ -2510,23 +2525,8 @@ static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) | |||
2510 | { | 2525 | { |
2511 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2526 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2512 | struct net_device *dev = info->user_ptr[1]; | 2527 | struct net_device *dev = info->user_ptr[1]; |
2513 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
2514 | int err; | ||
2515 | 2528 | ||
2516 | if (!rdev->ops->stop_ap) | 2529 | return cfg80211_stop_ap(rdev, dev); |
2517 | return -EOPNOTSUPP; | ||
2518 | |||
2519 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
2520 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
2521 | return -EOPNOTSUPP; | ||
2522 | |||
2523 | if (!wdev->beacon_interval) | ||
2524 | return -ENOENT; | ||
2525 | |||
2526 | err = rdev->ops->stop_ap(&rdev->wiphy, dev); | ||
2527 | if (!err) | ||
2528 | wdev->beacon_interval = 0; | ||
2529 | return err; | ||
2530 | } | 2530 | } |
2531 | 2531 | ||
2532 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | 2532 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { |
@@ -2618,7 +2618,8 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
2618 | int attr) | 2618 | int attr) |
2619 | { | 2619 | { |
2620 | struct nlattr *rate; | 2620 | struct nlattr *rate; |
2621 | u16 bitrate; | 2621 | u32 bitrate; |
2622 | u16 bitrate_compat; | ||
2622 | 2623 | ||
2623 | rate = nla_nest_start(msg, attr); | 2624 | rate = nla_nest_start(msg, attr); |
2624 | if (!rate) | 2625 | if (!rate) |
@@ -2626,8 +2627,12 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
2626 | 2627 | ||
2627 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ | 2628 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ |
2628 | bitrate = cfg80211_calculate_bitrate(info); | 2629 | bitrate = cfg80211_calculate_bitrate(info); |
2630 | /* report 16-bit bitrate only if we can */ | ||
2631 | bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0; | ||
2629 | if ((bitrate > 0 && | 2632 | if ((bitrate > 0 && |
2630 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate)) || | 2633 | nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) || |
2634 | (bitrate_compat > 0 && | ||
2635 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) || | ||
2631 | ((info->flags & RATE_INFO_FLAGS_MCS) && | 2636 | ((info->flags & RATE_INFO_FLAGS_MCS) && |
2632 | nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || | 2637 | nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || |
2633 | ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && | 2638 | ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && |
@@ -6276,6 +6281,7 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | |||
6276 | return cfg80211_leave_mesh(rdev, dev); | 6281 | return cfg80211_leave_mesh(rdev, dev); |
6277 | } | 6282 | } |
6278 | 6283 | ||
6284 | #ifdef CONFIG_PM | ||
6279 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | 6285 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) |
6280 | { | 6286 | { |
6281 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6287 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -6504,6 +6510,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6504 | kfree(new_triggers.patterns); | 6510 | kfree(new_triggers.patterns); |
6505 | return err; | 6511 | return err; |
6506 | } | 6512 | } |
6513 | #endif | ||
6507 | 6514 | ||
6508 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) | 6515 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) |
6509 | { | 6516 | { |
@@ -7158,6 +7165,7 @@ static struct genl_ops nl80211_ops[] = { | |||
7158 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7165 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
7159 | NL80211_FLAG_NEED_RTNL, | 7166 | NL80211_FLAG_NEED_RTNL, |
7160 | }, | 7167 | }, |
7168 | #ifdef CONFIG_PM | ||
7161 | { | 7169 | { |
7162 | .cmd = NL80211_CMD_GET_WOWLAN, | 7170 | .cmd = NL80211_CMD_GET_WOWLAN, |
7163 | .doit = nl80211_get_wowlan, | 7171 | .doit = nl80211_get_wowlan, |
@@ -7174,6 +7182,7 @@ static struct genl_ops nl80211_ops[] = { | |||
7174 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | 7182 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |
7175 | NL80211_FLAG_NEED_RTNL, | 7183 | NL80211_FLAG_NEED_RTNL, |
7176 | }, | 7184 | }, |
7185 | #endif | ||
7177 | { | 7186 | { |
7178 | .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, | 7187 | .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, |
7179 | .doit = nl80211_set_rekey_data, | 7188 | .doit = nl80211_set_rekey_data, |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index baf5704740ee..b2b32229b607 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -129,7 +129,7 @@ static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work); | |||
129 | 129 | ||
130 | /* We keep a static world regulatory domain in case of the absence of CRDA */ | 130 | /* We keep a static world regulatory domain in case of the absence of CRDA */ |
131 | static const struct ieee80211_regdomain world_regdom = { | 131 | static const struct ieee80211_regdomain world_regdom = { |
132 | .n_reg_rules = 5, | 132 | .n_reg_rules = 6, |
133 | .alpha2 = "00", | 133 | .alpha2 = "00", |
134 | .reg_rules = { | 134 | .reg_rules = { |
135 | /* IEEE 802.11b/g, channels 1..11 */ | 135 | /* IEEE 802.11b/g, channels 1..11 */ |
@@ -156,6 +156,9 @@ static const struct ieee80211_regdomain world_regdom = { | |||
156 | REG_RULE(5745-10, 5825+10, 40, 6, 20, | 156 | REG_RULE(5745-10, 5825+10, 40, 6, 20, |
157 | NL80211_RRF_PASSIVE_SCAN | | 157 | NL80211_RRF_PASSIVE_SCAN | |
158 | NL80211_RRF_NO_IBSS), | 158 | NL80211_RRF_NO_IBSS), |
159 | |||
160 | /* IEEE 802.11ad (60gHz), channels 1..3 */ | ||
161 | REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0), | ||
159 | } | 162 | } |
160 | }; | 163 | }; |
161 | 164 | ||
diff --git a/net/wireless/util.c b/net/wireless/util.c index 316cfd00914f..e31f1dba79ec 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -35,19 +35,29 @@ int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band) | |||
35 | { | 35 | { |
36 | /* see 802.11 17.3.8.3.2 and Annex J | 36 | /* see 802.11 17.3.8.3.2 and Annex J |
37 | * there are overlapping channel numbers in 5GHz and 2GHz bands */ | 37 | * there are overlapping channel numbers in 5GHz and 2GHz bands */ |
38 | if (band == IEEE80211_BAND_5GHZ) { | 38 | if (chan <= 0) |
39 | if (chan >= 182 && chan <= 196) | 39 | return 0; /* not supported */ |
40 | return 4000 + chan * 5; | 40 | switch (band) { |
41 | else | 41 | case IEEE80211_BAND_2GHZ: |
42 | return 5000 + chan * 5; | ||
43 | } else { /* IEEE80211_BAND_2GHZ */ | ||
44 | if (chan == 14) | 42 | if (chan == 14) |
45 | return 2484; | 43 | return 2484; |
46 | else if (chan < 14) | 44 | else if (chan < 14) |
47 | return 2407 + chan * 5; | 45 | return 2407 + chan * 5; |
46 | break; | ||
47 | case IEEE80211_BAND_5GHZ: | ||
48 | if (chan >= 182 && chan <= 196) | ||
49 | return 4000 + chan * 5; | ||
48 | else | 50 | else |
49 | return 0; /* not supported */ | 51 | return 5000 + chan * 5; |
52 | break; | ||
53 | case IEEE80211_BAND_60GHZ: | ||
54 | if (chan < 5) | ||
55 | return 56160 + chan * 2160; | ||
56 | break; | ||
57 | default: | ||
58 | ; | ||
50 | } | 59 | } |
60 | return 0; /* not supported */ | ||
51 | } | 61 | } |
52 | EXPORT_SYMBOL(ieee80211_channel_to_frequency); | 62 | EXPORT_SYMBOL(ieee80211_channel_to_frequency); |
53 | 63 | ||
@@ -60,8 +70,12 @@ int ieee80211_frequency_to_channel(int freq) | |||
60 | return (freq - 2407) / 5; | 70 | return (freq - 2407) / 5; |
61 | else if (freq >= 4910 && freq <= 4980) | 71 | else if (freq >= 4910 && freq <= 4980) |
62 | return (freq - 4000) / 5; | 72 | return (freq - 4000) / 5; |
63 | else | 73 | else if (freq <= 45000) /* DMG band lower limit */ |
64 | return (freq - 5000) / 5; | 74 | return (freq - 5000) / 5; |
75 | else if (freq >= 58320 && freq <= 64800) | ||
76 | return (freq - 56160) / 2160; | ||
77 | else | ||
78 | return 0; | ||
65 | } | 79 | } |
66 | EXPORT_SYMBOL(ieee80211_frequency_to_channel); | 80 | EXPORT_SYMBOL(ieee80211_frequency_to_channel); |
67 | 81 | ||
@@ -137,6 +151,11 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, | |||
137 | } | 151 | } |
138 | WARN_ON(want != 0 && want != 3 && want != 6); | 152 | WARN_ON(want != 0 && want != 3 && want != 6); |
139 | break; | 153 | break; |
154 | case IEEE80211_BAND_60GHZ: | ||
155 | /* check for mandatory HT MCS 1..4 */ | ||
156 | WARN_ON(!sband->ht_cap.ht_supported); | ||
157 | WARN_ON((sband->ht_cap.mcs.rx_mask[0] & 0x1e) != 0x1e); | ||
158 | break; | ||
140 | case IEEE80211_NUM_BANDS: | 159 | case IEEE80211_NUM_BANDS: |
141 | WARN_ON(1); | 160 | WARN_ON(1); |
142 | break; | 161 | break; |
@@ -805,8 +824,10 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
805 | return -EBUSY; | 824 | return -EBUSY; |
806 | 825 | ||
807 | if (ntype != otype && netif_running(dev)) { | 826 | if (ntype != otype && netif_running(dev)) { |
827 | mutex_lock(&rdev->devlist_mtx); | ||
808 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, | 828 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, |
809 | ntype); | 829 | ntype); |
830 | mutex_unlock(&rdev->devlist_mtx); | ||
810 | if (err) | 831 | if (err) |
811 | return err; | 832 | return err; |
812 | 833 | ||
@@ -814,6 +835,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
814 | dev->ieee80211_ptr->mesh_id_up_len = 0; | 835 | dev->ieee80211_ptr->mesh_id_up_len = 0; |
815 | 836 | ||
816 | switch (otype) { | 837 | switch (otype) { |
838 | case NL80211_IFTYPE_AP: | ||
839 | cfg80211_stop_ap(rdev, dev); | ||
840 | break; | ||
817 | case NL80211_IFTYPE_ADHOC: | 841 | case NL80211_IFTYPE_ADHOC: |
818 | cfg80211_leave_ibss(rdev, dev, false); | 842 | cfg80211_leave_ibss(rdev, dev, false); |
819 | break; | 843 | break; |
@@ -868,15 +892,69 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
868 | } | 892 | } |
869 | } | 893 | } |
870 | 894 | ||
895 | if (!err && ntype != otype && netif_running(dev)) { | ||
896 | cfg80211_update_iface_num(rdev, ntype, 1); | ||
897 | cfg80211_update_iface_num(rdev, otype, -1); | ||
898 | } | ||
899 | |||
871 | return err; | 900 | return err; |
872 | } | 901 | } |
873 | 902 | ||
874 | u16 cfg80211_calculate_bitrate(struct rate_info *rate) | 903 | static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate) |
904 | { | ||
905 | static const u32 __mcs2bitrate[] = { | ||
906 | /* control PHY */ | ||
907 | [0] = 275, | ||
908 | /* SC PHY */ | ||
909 | [1] = 3850, | ||
910 | [2] = 7700, | ||
911 | [3] = 9625, | ||
912 | [4] = 11550, | ||
913 | [5] = 12512, /* 1251.25 mbps */ | ||
914 | [6] = 15400, | ||
915 | [7] = 19250, | ||
916 | [8] = 23100, | ||
917 | [9] = 25025, | ||
918 | [10] = 30800, | ||
919 | [11] = 38500, | ||
920 | [12] = 46200, | ||
921 | /* OFDM PHY */ | ||
922 | [13] = 6930, | ||
923 | [14] = 8662, /* 866.25 mbps */ | ||
924 | [15] = 13860, | ||
925 | [16] = 17325, | ||
926 | [17] = 20790, | ||
927 | [18] = 27720, | ||
928 | [19] = 34650, | ||
929 | [20] = 41580, | ||
930 | [21] = 45045, | ||
931 | [22] = 51975, | ||
932 | [23] = 62370, | ||
933 | [24] = 67568, /* 6756.75 mbps */ | ||
934 | /* LP-SC PHY */ | ||
935 | [25] = 6260, | ||
936 | [26] = 8340, | ||
937 | [27] = 11120, | ||
938 | [28] = 12510, | ||
939 | [29] = 16680, | ||
940 | [30] = 22240, | ||
941 | [31] = 25030, | ||
942 | }; | ||
943 | |||
944 | if (WARN_ON_ONCE(rate->mcs >= ARRAY_SIZE(__mcs2bitrate))) | ||
945 | return 0; | ||
946 | |||
947 | return __mcs2bitrate[rate->mcs]; | ||
948 | } | ||
949 | |||
950 | u32 cfg80211_calculate_bitrate(struct rate_info *rate) | ||
875 | { | 951 | { |
876 | int modulation, streams, bitrate; | 952 | int modulation, streams, bitrate; |
877 | 953 | ||
878 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) | 954 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) |
879 | return rate->legacy; | 955 | return rate->legacy; |
956 | if (rate->flags & RATE_INFO_FLAGS_60G) | ||
957 | return cfg80211_calculate_bitrate_60g(rate); | ||
880 | 958 | ||
881 | /* the formula below does only work for MCS values smaller than 32 */ | 959 | /* the formula below does only work for MCS values smaller than 32 */ |
882 | if (WARN_ON_ONCE(rate->mcs >= 32)) | 960 | if (WARN_ON_ONCE(rate->mcs >= 32)) |
@@ -930,27 +1008,48 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
930 | return res; | 1008 | return res; |
931 | } | 1009 | } |
932 | 1010 | ||
933 | int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | 1011 | int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, |
934 | struct wireless_dev *wdev, | 1012 | struct wireless_dev *wdev, |
935 | enum nl80211_iftype iftype) | 1013 | enum nl80211_iftype iftype, |
1014 | struct ieee80211_channel *chan, | ||
1015 | enum cfg80211_chan_mode chanmode) | ||
936 | { | 1016 | { |
937 | struct wireless_dev *wdev_iter; | 1017 | struct wireless_dev *wdev_iter; |
938 | u32 used_iftypes = BIT(iftype); | 1018 | u32 used_iftypes = BIT(iftype); |
939 | int num[NUM_NL80211_IFTYPES]; | 1019 | int num[NUM_NL80211_IFTYPES]; |
1020 | struct ieee80211_channel | ||
1021 | *used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS]; | ||
1022 | struct ieee80211_channel *ch; | ||
1023 | enum cfg80211_chan_mode chmode; | ||
1024 | int num_different_channels = 0; | ||
940 | int total = 1; | 1025 | int total = 1; |
941 | int i, j; | 1026 | int i, j; |
942 | 1027 | ||
943 | ASSERT_RTNL(); | 1028 | ASSERT_RTNL(); |
1029 | lockdep_assert_held(&rdev->devlist_mtx); | ||
944 | 1030 | ||
945 | /* Always allow software iftypes */ | 1031 | /* Always allow software iftypes */ |
946 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | 1032 | if (rdev->wiphy.software_iftypes & BIT(iftype)) |
947 | return 0; | 1033 | return 0; |
948 | 1034 | ||
949 | memset(num, 0, sizeof(num)); | 1035 | memset(num, 0, sizeof(num)); |
1036 | memset(used_channels, 0, sizeof(used_channels)); | ||
950 | 1037 | ||
951 | num[iftype] = 1; | 1038 | num[iftype] = 1; |
952 | 1039 | ||
953 | mutex_lock(&rdev->devlist_mtx); | 1040 | switch (chanmode) { |
1041 | case CHAN_MODE_UNDEFINED: | ||
1042 | break; | ||
1043 | case CHAN_MODE_SHARED: | ||
1044 | WARN_ON(!chan); | ||
1045 | used_channels[0] = chan; | ||
1046 | num_different_channels++; | ||
1047 | break; | ||
1048 | case CHAN_MODE_EXCLUSIVE: | ||
1049 | num_different_channels++; | ||
1050 | break; | ||
1051 | } | ||
1052 | |||
954 | list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { | 1053 | list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { |
955 | if (wdev_iter == wdev) | 1054 | if (wdev_iter == wdev) |
956 | continue; | 1055 | continue; |
@@ -960,11 +1059,33 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
960 | if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) | 1059 | if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) |
961 | continue; | 1060 | continue; |
962 | 1061 | ||
1062 | cfg80211_get_chan_state(rdev, wdev_iter, &ch, &chmode); | ||
1063 | |||
1064 | switch (chmode) { | ||
1065 | case CHAN_MODE_UNDEFINED: | ||
1066 | break; | ||
1067 | case CHAN_MODE_SHARED: | ||
1068 | for (i = 0; i < CFG80211_MAX_NUM_DIFFERENT_CHANNELS; i++) | ||
1069 | if (!used_channels[i] || used_channels[i] == ch) | ||
1070 | break; | ||
1071 | |||
1072 | if (i == CFG80211_MAX_NUM_DIFFERENT_CHANNELS) | ||
1073 | return -EBUSY; | ||
1074 | |||
1075 | if (used_channels[i] == NULL) { | ||
1076 | used_channels[i] = ch; | ||
1077 | num_different_channels++; | ||
1078 | } | ||
1079 | break; | ||
1080 | case CHAN_MODE_EXCLUSIVE: | ||
1081 | num_different_channels++; | ||
1082 | break; | ||
1083 | } | ||
1084 | |||
963 | num[wdev_iter->iftype]++; | 1085 | num[wdev_iter->iftype]++; |
964 | total++; | 1086 | total++; |
965 | used_iftypes |= BIT(wdev_iter->iftype); | 1087 | used_iftypes |= BIT(wdev_iter->iftype); |
966 | } | 1088 | } |
967 | mutex_unlock(&rdev->devlist_mtx); | ||
968 | 1089 | ||
969 | if (total == 1) | 1090 | if (total == 1) |
970 | return 0; | 1091 | return 0; |
@@ -976,12 +1097,15 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
976 | 1097 | ||
977 | c = &rdev->wiphy.iface_combinations[i]; | 1098 | c = &rdev->wiphy.iface_combinations[i]; |
978 | 1099 | ||
1100 | if (total > c->max_interfaces) | ||
1101 | continue; | ||
1102 | if (num_different_channels > c->num_different_channels) | ||
1103 | continue; | ||
1104 | |||
979 | limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, | 1105 | limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, |
980 | GFP_KERNEL); | 1106 | GFP_KERNEL); |
981 | if (!limits) | 1107 | if (!limits) |
982 | return -ENOMEM; | 1108 | return -ENOMEM; |
983 | if (total > c->max_interfaces) | ||
984 | goto cont; | ||
985 | 1109 | ||
986 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { | 1110 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { |
987 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | 1111 | if (rdev->wiphy.software_iftypes & BIT(iftype)) |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index bc879833b21f..7df42f541873 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -827,8 +827,6 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, | |||
827 | { | 827 | { |
828 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 828 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
829 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 829 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
830 | struct ieee80211_channel *chan; | ||
831 | enum nl80211_channel_type channel_type; | ||
832 | 830 | ||
833 | switch (wdev->iftype) { | 831 | switch (wdev->iftype) { |
834 | case NL80211_IFTYPE_STATION: | 832 | case NL80211_IFTYPE_STATION: |
@@ -836,13 +834,10 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, | |||
836 | case NL80211_IFTYPE_ADHOC: | 834 | case NL80211_IFTYPE_ADHOC: |
837 | return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); | 835 | return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); |
838 | case NL80211_IFTYPE_MONITOR: | 836 | case NL80211_IFTYPE_MONITOR: |
839 | if (!rdev->ops->get_channel) | 837 | if (!rdev->monitor_channel) |
840 | return -EINVAL; | 838 | return -EINVAL; |
841 | 839 | ||
842 | chan = rdev->ops->get_channel(wdev->wiphy, &channel_type); | 840 | freq->m = rdev->monitor_channel->center_freq; |
843 | if (!chan) | ||
844 | return -EINVAL; | ||
845 | freq->m = chan->center_freq; | ||
846 | freq->e = 6; | 841 | freq->e = 6; |
847 | return 0; | 842 | return 0; |
848 | default: | 843 | default: |