aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2010-05-11 14:24:55 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-05-11 14:24:55 -0400
commitcc755896a4274f11283bca32d1d658203844057a (patch)
tree218970ece71df99f686b9416b7fd88b921690ebb /net
parentd250fe91ae129bff0968e685cc9c466d3a5e3482 (diff)
parent9459d59fbf0bc82ff4c804679fa8bc22788eca63 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts: drivers/net/wireless/ath/ar9170/main.c
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/Makefile3
-rw-r--r--net/mac80211/cfg.c58
-rw-r--r--net/mac80211/chan.c127
-rw-r--r--net/mac80211/ibss.c5
-rw-r--r--net/mac80211/ieee80211_i.h16
-rw-r--r--net/mac80211/main.c2
-rw-r--r--net/mac80211/mlme.c44
-rw-r--r--net/mac80211/tx.c5
-rw-r--r--net/mac80211/util.c25
-rw-r--r--net/wireless/chan.c56
-rw-r--r--net/wireless/core.h12
-rw-r--r--net/wireless/ibss.c5
-rw-r--r--net/wireless/nl80211.c171
-rw-r--r--net/wireless/sme.c5
-rw-r--r--net/wireless/wext-compat.c15
-rw-r--r--net/wireless/wext-sme.c2
16 files changed, 412 insertions, 139 deletions
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 04420291e7ad..84b48ba8a77e 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -23,7 +23,8 @@ mac80211-y := \
23 key.o \ 23 key.o \
24 util.o \ 24 util.o \
25 wme.o \ 25 wme.o \
26 event.o 26 event.o \
27 chan.o
27 28
28mac80211-$(CONFIG_MAC80211_LEDS) += led.o 29mac80211-$(CONFIG_MAC80211_LEDS) += led.o
29mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ 30mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index ae37270a0633..c7000a6ca379 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1162,15 +1162,39 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
1162} 1162}
1163 1163
1164static int ieee80211_set_channel(struct wiphy *wiphy, 1164static int ieee80211_set_channel(struct wiphy *wiphy,
1165 struct net_device *netdev,
1165 struct ieee80211_channel *chan, 1166 struct ieee80211_channel *chan,
1166 enum nl80211_channel_type channel_type) 1167 enum nl80211_channel_type channel_type)
1167{ 1168{
1168 struct ieee80211_local *local = wiphy_priv(wiphy); 1169 struct ieee80211_local *local = wiphy_priv(wiphy);
1170 struct ieee80211_sub_if_data *sdata = NULL;
1171
1172 if (netdev)
1173 sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
1174
1175 switch (ieee80211_get_channel_mode(local, NULL)) {
1176 case CHAN_MODE_HOPPING:
1177 return -EBUSY;
1178 case CHAN_MODE_FIXED:
1179 if (local->oper_channel != chan)
1180 return -EBUSY;
1181 if (!sdata && local->_oper_channel_type == channel_type)
1182 return 0;
1183 break;
1184 case CHAN_MODE_UNDEFINED:
1185 break;
1186 }
1169 1187
1170 local->oper_channel = chan; 1188 local->oper_channel = chan;
1171 local->oper_channel_type = channel_type;
1172 1189
1173 return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); 1190 if (!ieee80211_set_channel_type(local, sdata, channel_type))
1191 return -EBUSY;
1192
1193 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
1194 if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR)
1195 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
1196
1197 return 0;
1174} 1198}
1175 1199
1176#ifdef CONFIG_PM 1200#ifdef CONFIG_PM
@@ -1214,6 +1238,20 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
1214static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, 1238static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
1215 struct cfg80211_assoc_request *req) 1239 struct cfg80211_assoc_request *req)
1216{ 1240{
1241 struct ieee80211_local *local = wiphy_priv(wiphy);
1242 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1243
1244 switch (ieee80211_get_channel_mode(local, sdata)) {
1245 case CHAN_MODE_HOPPING:
1246 return -EBUSY;
1247 case CHAN_MODE_FIXED:
1248 if (local->oper_channel == req->bss->channel)
1249 break;
1250 return -EBUSY;
1251 case CHAN_MODE_UNDEFINED:
1252 break;
1253 }
1254
1217 return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req); 1255 return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
1218} 1256}
1219 1257
@@ -1236,8 +1274,22 @@ static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
1236static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, 1274static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
1237 struct cfg80211_ibss_params *params) 1275 struct cfg80211_ibss_params *params)
1238{ 1276{
1277 struct ieee80211_local *local = wiphy_priv(wiphy);
1239 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1278 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1240 1279
1280 switch (ieee80211_get_channel_mode(local, sdata)) {
1281 case CHAN_MODE_HOPPING:
1282 return -EBUSY;
1283 case CHAN_MODE_FIXED:
1284 if (!params->channel_fixed)
1285 return -EBUSY;
1286 if (local->oper_channel == params->channel)
1287 break;
1288 return -EBUSY;
1289 case CHAN_MODE_UNDEFINED:
1290 break;
1291 }
1292
1241 return ieee80211_ibss_join(sdata, params); 1293 return ieee80211_ibss_join(sdata, params);
1242} 1294}
1243 1295
@@ -1366,7 +1418,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
1366 * association, there's no need to send an action frame. 1418 * association, there's no need to send an action frame.
1367 */ 1419 */
1368 if (!sdata->u.mgd.associated || 1420 if (!sdata->u.mgd.associated ||
1369 sdata->local->oper_channel_type == NL80211_CHAN_NO_HT) { 1421 sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) {
1370 mutex_lock(&sdata->local->iflist_mtx); 1422 mutex_lock(&sdata->local->iflist_mtx);
1371 ieee80211_recalc_smps(sdata->local, sdata); 1423 ieee80211_recalc_smps(sdata->local, sdata);
1372 mutex_unlock(&sdata->local->iflist_mtx); 1424 mutex_unlock(&sdata->local->iflist_mtx);
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
new file mode 100644
index 000000000000..5d218c530a4e
--- /dev/null
+++ b/net/mac80211/chan.c
@@ -0,0 +1,127 @@
1/*
2 * mac80211 - channel management
3 */
4
5#include <linux/nl80211.h>
6#include "ieee80211_i.h"
7
8enum ieee80211_chan_mode
9__ieee80211_get_channel_mode(struct ieee80211_local *local,
10 struct ieee80211_sub_if_data *ignore)
11{
12 struct ieee80211_sub_if_data *sdata;
13
14 WARN_ON(!mutex_is_locked(&local->iflist_mtx));
15
16 list_for_each_entry(sdata, &local->interfaces, list) {
17 if (sdata == ignore)
18 continue;
19
20 if (!ieee80211_sdata_running(sdata))
21 continue;
22
23 if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
24 continue;
25
26 if (sdata->vif.type == NL80211_IFTYPE_STATION &&
27 !sdata->u.mgd.associated)
28 continue;
29
30 if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
31 if (!sdata->u.ibss.ssid_len)
32 continue;
33 if (!sdata->u.ibss.fixed_channel)
34 return CHAN_MODE_HOPPING;
35 }
36
37 if (sdata->vif.type == NL80211_IFTYPE_AP &&
38 !sdata->u.ap.beacon)
39 continue;
40
41 return CHAN_MODE_FIXED;
42 }
43
44 return CHAN_MODE_UNDEFINED;
45}
46
47enum ieee80211_chan_mode
48ieee80211_get_channel_mode(struct ieee80211_local *local,
49 struct ieee80211_sub_if_data *ignore)
50{
51 enum ieee80211_chan_mode mode;
52
53 mutex_lock(&local->iflist_mtx);
54 mode = __ieee80211_get_channel_mode(local, ignore);
55 mutex_unlock(&local->iflist_mtx);
56
57 return mode;
58}
59
60bool ieee80211_set_channel_type(struct ieee80211_local *local,
61 struct ieee80211_sub_if_data *sdata,
62 enum nl80211_channel_type chantype)
63{
64 struct ieee80211_sub_if_data *tmp;
65 enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT;
66 bool result;
67
68 mutex_lock(&local->iflist_mtx);
69
70 list_for_each_entry(tmp, &local->interfaces, list) {
71 if (tmp == sdata)
72 continue;
73
74 if (!ieee80211_sdata_running(tmp))
75 continue;
76
77 switch (tmp->vif.bss_conf.channel_type) {
78 case NL80211_CHAN_NO_HT:
79 case NL80211_CHAN_HT20:
80 superchan = tmp->vif.bss_conf.channel_type;
81 break;
82 case NL80211_CHAN_HT40PLUS:
83 WARN_ON(superchan == NL80211_CHAN_HT40MINUS);
84 superchan = NL80211_CHAN_HT40PLUS;
85 break;
86 case NL80211_CHAN_HT40MINUS:
87 WARN_ON(superchan == NL80211_CHAN_HT40PLUS);
88 superchan = NL80211_CHAN_HT40MINUS;
89 break;
90 }
91 }
92
93 switch (superchan) {
94 case NL80211_CHAN_NO_HT:
95 case NL80211_CHAN_HT20:
96 /*
97 * allow any change that doesn't go to no-HT
98 * (if it already is no-HT no change is needed)
99 */
100 if (chantype == NL80211_CHAN_NO_HT)
101 break;
102 superchan = chantype;
103 break;
104 case NL80211_CHAN_HT40PLUS:
105 case NL80211_CHAN_HT40MINUS:
106 /* allow smaller bandwidth and same */
107 if (chantype == NL80211_CHAN_NO_HT)
108 break;
109 if (chantype == NL80211_CHAN_HT20)
110 break;
111 if (superchan == chantype)
112 break;
113 result = false;
114 goto out;
115 }
116
117 local->_oper_channel_type = superchan;
118
119 if (sdata)
120 sdata->vif.bss_conf.channel_type = chantype;
121
122 result = true;
123 out:
124 mutex_unlock(&local->iflist_mtx);
125
126 return result;
127}
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index b72ee6435fa3..b2cc1fda6cfd 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -103,7 +103,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
103 sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; 103 sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
104 104
105 local->oper_channel = chan; 105 local->oper_channel = chan;
106 local->oper_channel_type = NL80211_CHAN_NO_HT; 106 WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
107 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); 107 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
108 108
109 sband = local->hw.wiphy->bands[chan->band]; 109 sband = local->hw.wiphy->bands[chan->band];
@@ -911,7 +911,8 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
911 /* fix ourselves to that channel now already */ 911 /* fix ourselves to that channel now already */
912 if (params->channel_fixed) { 912 if (params->channel_fixed) {
913 sdata->local->oper_channel = params->channel; 913 sdata->local->oper_channel = params->channel;
914 sdata->local->oper_channel_type = NL80211_CHAN_NO_HT; 914 WARN_ON(!ieee80211_set_channel_type(sdata->local, sdata,
915 NL80211_CHAN_NO_HT));
915 } 916 }
916 917
917 if (params->ie) { 918 if (params->ie) {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index cbaf4981e110..7ef7798d04cd 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -767,7 +767,7 @@ struct ieee80211_local {
767 enum mac80211_scan_state next_scan_state; 767 enum mac80211_scan_state next_scan_state;
768 struct delayed_work scan_work; 768 struct delayed_work scan_work;
769 struct ieee80211_sub_if_data *scan_sdata; 769 struct ieee80211_sub_if_data *scan_sdata;
770 enum nl80211_channel_type oper_channel_type; 770 enum nl80211_channel_type _oper_channel_type;
771 struct ieee80211_channel *oper_channel, *csa_channel; 771 struct ieee80211_channel *oper_channel, *csa_channel;
772 772
773 /* Temporary remain-on-channel for off-channel operations */ 773 /* Temporary remain-on-channel for off-channel operations */
@@ -1228,6 +1228,20 @@ int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
1228int ieee80211_wk_cancel_remain_on_channel( 1228int ieee80211_wk_cancel_remain_on_channel(
1229 struct ieee80211_sub_if_data *sdata, u64 cookie); 1229 struct ieee80211_sub_if_data *sdata, u64 cookie);
1230 1230
1231/* channel management */
1232enum ieee80211_chan_mode {
1233 CHAN_MODE_UNDEFINED,
1234 CHAN_MODE_HOPPING,
1235 CHAN_MODE_FIXED,
1236};
1237
1238enum ieee80211_chan_mode
1239ieee80211_get_channel_mode(struct ieee80211_local *local,
1240 struct ieee80211_sub_if_data *ignore);
1241bool ieee80211_set_channel_type(struct ieee80211_local *local,
1242 struct ieee80211_sub_if_data *sdata,
1243 enum nl80211_channel_type chantype);
1244
1231#ifdef CONFIG_MAC80211_NOINLINE 1245#ifdef CONFIG_MAC80211_NOINLINE
1232#define debug_noinline noinline 1246#define debug_noinline noinline
1233#else 1247#else
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index bd632e1ee2c5..22a384dfab65 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -111,7 +111,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
111 channel_type = local->tmp_channel_type; 111 channel_type = local->tmp_channel_type;
112 } else { 112 } else {
113 chan = local->oper_channel; 113 chan = local->oper_channel;
114 channel_type = local->oper_channel_type; 114 channel_type = local->_oper_channel_type;
115 } 115 }
116 116
117 if (chan != local->hw.conf.channel || 117 if (chan != local->hw.conf.channel ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 358226f63b81..11783192a625 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -137,11 +137,14 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
137 struct sta_info *sta; 137 struct sta_info *sta;
138 u32 changed = 0; 138 u32 changed = 0;
139 u16 ht_opmode; 139 u16 ht_opmode;
140 bool enable_ht = true, ht_changed; 140 bool enable_ht = true;
141 enum nl80211_channel_type prev_chantype;
141 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; 142 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
142 143
143 sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 144 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
144 145
146 prev_chantype = sdata->vif.bss_conf.channel_type;
147
145 /* HT is not supported */ 148 /* HT is not supported */
146 if (!sband->ht_cap.ht_supported) 149 if (!sband->ht_cap.ht_supported)
147 enable_ht = false; 150 enable_ht = false;
@@ -172,38 +175,37 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
172 } 175 }
173 } 176 }
174 177
175 ht_changed = conf_is_ht(&local->hw.conf) != enable_ht ||
176 channel_type != local->hw.conf.channel_type;
177
178 if (local->tmp_channel) 178 if (local->tmp_channel)
179 local->tmp_channel_type = channel_type; 179 local->tmp_channel_type = channel_type;
180 local->oper_channel_type = channel_type;
181 180
182 if (ht_changed) { 181 if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
183 /* channel_type change automatically detected */ 182 /* can only fail due to HT40+/- mismatch */
184 ieee80211_hw_config(local, 0); 183 channel_type = NL80211_CHAN_HT20;
184 WARN_ON(!ieee80211_set_channel_type(local, sdata, channel_type));
185 }
185 186
187 /* channel_type change automatically detected */
188 ieee80211_hw_config(local, 0);
189
190 if (prev_chantype != channel_type) {
186 rcu_read_lock(); 191 rcu_read_lock();
187 sta = sta_info_get(sdata, bssid); 192 sta = sta_info_get(sdata, bssid);
188 if (sta) 193 if (sta)
189 rate_control_rate_update(local, sband, sta, 194 rate_control_rate_update(local, sband, sta,
190 IEEE80211_RC_HT_CHANGED, 195 IEEE80211_RC_HT_CHANGED,
191 local->oper_channel_type); 196 channel_type);
192 rcu_read_unlock(); 197 rcu_read_unlock();
193 } 198 }
194
195 /* disable HT */
196 if (!enable_ht)
197 return 0;
198 199
199 ht_opmode = le16_to_cpu(hti->operation_mode); 200 ht_opmode = le16_to_cpu(hti->operation_mode);
200 201
201 /* if bss configuration changed store the new one */ 202 /* if bss configuration changed store the new one */
202 if (!sdata->ht_opmode_valid || 203 if (sdata->ht_opmode_valid != enable_ht ||
203 sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { 204 sdata->vif.bss_conf.ht_operation_mode != ht_opmode ||
205 prev_chantype != channel_type) {
204 changed |= BSS_CHANGED_HT; 206 changed |= BSS_CHANGED_HT;
205 sdata->vif.bss_conf.ht_operation_mode = ht_opmode; 207 sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
206 sdata->ht_opmode_valid = true; 208 sdata->ht_opmode_valid = enable_ht;
207 } 209 }
208 210
209 return changed; 211 return changed;
@@ -866,7 +868,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
866 ieee80211_set_wmm_default(sdata); 868 ieee80211_set_wmm_default(sdata);
867 869
868 /* channel(_type) changes are handled by ieee80211_hw_config */ 870 /* channel(_type) changes are handled by ieee80211_hw_config */
869 local->oper_channel_type = NL80211_CHAN_NO_HT; 871 WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
870 872
871 /* on the next assoc, re-program HT parameters */ 873 /* on the next assoc, re-program HT parameters */
872 sdata->ht_opmode_valid = false; 874 sdata->ht_opmode_valid = false;
@@ -883,8 +885,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
883 885
884 ieee80211_hw_config(local, config_changed); 886 ieee80211_hw_config(local, config_changed);
885 887
886 /* And the BSSID changed -- not very interesting here */ 888 /* The BSSID (not really interesting) and HT changed */
887 changed |= BSS_CHANGED_BSSID; 889 changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
888 ieee80211_bss_info_change_notify(sdata, changed); 890 ieee80211_bss_info_change_notify(sdata, changed);
889 891
890 if (remove_sta) 892 if (remove_sta)
@@ -2266,7 +2268,7 @@ int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
2266 if ((chan != local->tmp_channel || 2268 if ((chan != local->tmp_channel ||
2267 channel_type != local->tmp_channel_type) && 2269 channel_type != local->tmp_channel_type) &&
2268 (chan != local->oper_channel || 2270 (chan != local->oper_channel ||
2269 channel_type != local->oper_channel_type)) 2271 channel_type != local->_oper_channel_type))
2270 return -EBUSY; 2272 return -EBUSY;
2271 2273
2272 skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); 2274 skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index f3841f43249e..680bcb7093db 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2251,8 +2251,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2251 2251
2252 info->control.vif = vif; 2252 info->control.vif = vif;
2253 2253
2254 info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; 2254 info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT |
2255 info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; 2255 IEEE80211_TX_CTL_ASSIGN_SEQ |
2256 IEEE80211_TX_CTL_FIRST_FRAGMENT;
2256 out: 2257 out:
2257 rcu_read_unlock(); 2258 rcu_read_unlock();
2258 return skb; 2259 return skb;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 2b75b4fb68f4..5b79d552780a 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1160,18 +1160,33 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1160 1160
1161 /* Finally also reconfigure all the BSS information */ 1161 /* Finally also reconfigure all the BSS information */
1162 list_for_each_entry(sdata, &local->interfaces, list) { 1162 list_for_each_entry(sdata, &local->interfaces, list) {
1163 u32 changed = ~0; 1163 u32 changed;
1164
1164 if (!ieee80211_sdata_running(sdata)) 1165 if (!ieee80211_sdata_running(sdata))
1165 continue; 1166 continue;
1167
1168 /* common change flags for all interface types */
1169 changed = BSS_CHANGED_ERP_CTS_PROT |
1170 BSS_CHANGED_ERP_PREAMBLE |
1171 BSS_CHANGED_ERP_SLOT |
1172 BSS_CHANGED_HT |
1173 BSS_CHANGED_BASIC_RATES |
1174 BSS_CHANGED_BEACON_INT |
1175 BSS_CHANGED_BSSID |
1176 BSS_CHANGED_CQM;
1177
1166 switch (sdata->vif.type) { 1178 switch (sdata->vif.type) {
1167 case NL80211_IFTYPE_STATION: 1179 case NL80211_IFTYPE_STATION:
1168 /* disable beacon change bits */ 1180 changed |= BSS_CHANGED_ASSOC;
1169 changed &= ~(BSS_CHANGED_BEACON | 1181 ieee80211_bss_info_change_notify(sdata, changed);
1170 BSS_CHANGED_BEACON_ENABLED); 1182 break;
1171 /* fall through */
1172 case NL80211_IFTYPE_ADHOC: 1183 case NL80211_IFTYPE_ADHOC:
1184 changed |= BSS_CHANGED_IBSS;
1185 /* fall through */
1173 case NL80211_IFTYPE_AP: 1186 case NL80211_IFTYPE_AP:
1174 case NL80211_IFTYPE_MESH_POINT: 1187 case NL80211_IFTYPE_MESH_POINT:
1188 changed |= BSS_CHANGED_BEACON |
1189 BSS_CHANGED_BEACON_ENABLED;
1175 ieee80211_bss_info_change_notify(sdata, changed); 1190 ieee80211_bss_info_change_notify(sdata, changed);
1176 break; 1191 break;
1177 case NL80211_IFTYPE_WDS: 1192 case NL80211_IFTYPE_WDS:
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index bf1737fc9a7e..d92d088026bf 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -10,38 +10,6 @@
10#include "core.h" 10#include "core.h"
11 11
12struct ieee80211_channel * 12struct ieee80211_channel *
13rdev_fixed_channel(struct cfg80211_registered_device *rdev,
14 struct wireless_dev *for_wdev)
15{
16 struct wireless_dev *wdev;
17 struct ieee80211_channel *result = NULL;
18
19 WARN_ON(!mutex_is_locked(&rdev->devlist_mtx));
20
21 list_for_each_entry(wdev, &rdev->netdev_list, list) {
22 if (wdev == for_wdev)
23 continue;
24
25 /*
26 * Lock manually to tell lockdep about allowed
27 * nesting here if for_wdev->mtx is held already.
28 * This is ok as it's all under the rdev devlist
29 * mutex and as such can only be done once at any
30 * given time.
31 */
32 mutex_lock_nested(&wdev->mtx, SINGLE_DEPTH_NESTING);
33 if (wdev->current_bss)
34 result = wdev->current_bss->pub.channel;
35 wdev_unlock(wdev);
36
37 if (result)
38 break;
39 }
40
41 return result;
42}
43
44struct ieee80211_channel *
45rdev_freq_to_chan(struct cfg80211_registered_device *rdev, 13rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
46 int freq, enum nl80211_channel_type channel_type) 14 int freq, enum nl80211_channel_type channel_type)
47{ 15{
@@ -75,15 +43,22 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
75 return chan; 43 return chan;
76} 44}
77 45
78int rdev_set_freq(struct cfg80211_registered_device *rdev, 46int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
79 struct wireless_dev *for_wdev, 47 struct wireless_dev *wdev, int freq,
80 int freq, enum nl80211_channel_type channel_type) 48 enum nl80211_channel_type channel_type)
81{ 49{
82 struct ieee80211_channel *chan; 50 struct ieee80211_channel *chan;
83 int result; 51 int result;
84 52
85 if (rdev_fixed_channel(rdev, for_wdev)) 53 if (wdev->iftype == NL80211_IFTYPE_MONITOR)
86 return -EBUSY; 54 wdev = NULL;
55
56 if (wdev) {
57 ASSERT_WDEV_LOCK(wdev);
58
59 if (!netif_running(wdev->netdev))
60 return -ENETDOWN;
61 }
87 62
88 if (!rdev->ops->set_channel) 63 if (!rdev->ops->set_channel)
89 return -EOPNOTSUPP; 64 return -EOPNOTSUPP;
@@ -92,11 +67,14 @@ int rdev_set_freq(struct cfg80211_registered_device *rdev,
92 if (!chan) 67 if (!chan)
93 return -EINVAL; 68 return -EINVAL;
94 69
95 result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type); 70 result = rdev->ops->set_channel(&rdev->wiphy,
71 wdev ? wdev->netdev : NULL,
72 chan, channel_type);
96 if (result) 73 if (result)
97 return result; 74 return result;
98 75
99 rdev->channel = chan; 76 if (wdev)
77 wdev->channel = chan;
100 78
101 return 0; 79 return 0;
102} 80}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index b2234b436ead..ae930acf75e9 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -70,9 +70,6 @@ struct cfg80211_registered_device {
70 struct work_struct conn_work; 70 struct work_struct conn_work;
71 struct work_struct event_work; 71 struct work_struct event_work;
72 72
73 /* current channel */
74 struct ieee80211_channel *channel;
75
76 /* must be last because of the way we do wiphy_priv(), 73 /* must be last because of the way we do wiphy_priv(),
77 * and it should at least be aligned to NETDEV_ALIGN */ 74 * and it should at least be aligned to NETDEV_ALIGN */
78 struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); 75 struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
@@ -388,14 +385,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
388void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); 385void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
389 386
390struct ieee80211_channel * 387struct ieee80211_channel *
391rdev_fixed_channel(struct cfg80211_registered_device *rdev,
392 struct wireless_dev *for_wdev);
393struct ieee80211_channel *
394rdev_freq_to_chan(struct cfg80211_registered_device *rdev, 388rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
395 int freq, enum nl80211_channel_type channel_type); 389 int freq, enum nl80211_channel_type channel_type);
396int rdev_set_freq(struct cfg80211_registered_device *rdev, 390int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
397 struct wireless_dev *for_wdev, 391 struct wireless_dev *wdev, int freq,
398 int freq, enum nl80211_channel_type channel_type); 392 enum nl80211_channel_type channel_type);
399 393
400u16 cfg80211_calculate_bitrate(struct rate_info *rate); 394u16 cfg80211_calculate_bitrate(struct rate_info *rate);
401 395
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 6a5acf750174..adcabba02e20 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -81,15 +81,10 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
81 struct cfg80211_cached_keys *connkeys) 81 struct cfg80211_cached_keys *connkeys)
82{ 82{
83 struct wireless_dev *wdev = dev->ieee80211_ptr; 83 struct wireless_dev *wdev = dev->ieee80211_ptr;
84 struct ieee80211_channel *chan;
85 int err; 84 int err;
86 85
87 ASSERT_WDEV_LOCK(wdev); 86 ASSERT_WDEV_LOCK(wdev);
88 87
89 chan = rdev_fixed_channel(rdev, wdev);
90 if (chan && chan != params->channel)
91 return -EBUSY;
92
93 if (wdev->ssid_len) 88 if (wdev->ssid_len)
94 return -EALREADY; 89 return -EALREADY;
95 90
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 01da83ddcff7..aaa1aad566cd 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -589,6 +589,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
589 i++; 589 i++;
590 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); 590 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
591 } 591 }
592 CMD(set_channel, SET_CHANNEL);
592 593
593#undef CMD 594#undef CMD
594 595
@@ -689,10 +690,90 @@ static int parse_txq_params(struct nlattr *tb[],
689 return 0; 690 return 0;
690} 691}
691 692
693static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
694{
695 /*
696 * You can only set the channel explicitly for AP, mesh
697 * and WDS type interfaces; all others have their channel
698 * managed via their respective "establish a connection"
699 * command (connect, join, ...)
700 *
701 * Monitors are special as they are normally slaved to
702 * whatever else is going on, so they behave as though
703 * you tried setting the wiphy channel itself.
704 */
705 return !wdev ||
706 wdev->iftype == NL80211_IFTYPE_AP ||
707 wdev->iftype == NL80211_IFTYPE_WDS ||
708 wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
709 wdev->iftype == NL80211_IFTYPE_MONITOR;
710}
711
712static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
713 struct wireless_dev *wdev,
714 struct genl_info *info)
715{
716 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
717 u32 freq;
718 int result;
719
720 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
721 return -EINVAL;
722
723 if (!nl80211_can_set_dev_channel(wdev))
724 return -EOPNOTSUPP;
725
726 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
727 channel_type = nla_get_u32(info->attrs[
728 NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
729 if (channel_type != NL80211_CHAN_NO_HT &&
730 channel_type != NL80211_CHAN_HT20 &&
731 channel_type != NL80211_CHAN_HT40PLUS &&
732 channel_type != NL80211_CHAN_HT40MINUS)
733 return -EINVAL;
734 }
735
736 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
737
738 mutex_lock(&rdev->devlist_mtx);
739 if (wdev) {
740 wdev_lock(wdev);
741 result = cfg80211_set_freq(rdev, wdev, freq, channel_type);
742 wdev_unlock(wdev);
743 } else {
744 result = cfg80211_set_freq(rdev, NULL, freq, channel_type);
745 }
746 mutex_unlock(&rdev->devlist_mtx);
747
748 return result;
749}
750
751static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
752{
753 struct cfg80211_registered_device *rdev;
754 struct net_device *netdev;
755 int result;
756
757 rtnl_lock();
758
759 result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev);
760 if (result)
761 goto unlock;
762
763 result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info);
764
765 unlock:
766 rtnl_unlock();
767
768 return result;
769}
770
692static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) 771static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
693{ 772{
694 struct cfg80211_registered_device *rdev; 773 struct cfg80211_registered_device *rdev;
695 int result = 0, rem_txq_params = 0; 774 struct net_device *netdev = NULL;
775 struct wireless_dev *wdev;
776 int result, rem_txq_params = 0;
696 struct nlattr *nl_txq_params; 777 struct nlattr *nl_txq_params;
697 u32 changed; 778 u32 changed;
698 u8 retry_short = 0, retry_long = 0; 779 u8 retry_short = 0, retry_long = 0;
@@ -701,16 +782,50 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
701 782
702 rtnl_lock(); 783 rtnl_lock();
703 784
785 /*
786 * Try to find the wiphy and netdev. Normally this
787 * function shouldn't need the netdev, but this is
788 * done for backward compatibility -- previously
789 * setting the channel was done per wiphy, but now
790 * it is per netdev. Previous userland like hostapd
791 * also passed a netdev to set_wiphy, so that it is
792 * possible to let that go to the right netdev!
793 */
704 mutex_lock(&cfg80211_mutex); 794 mutex_lock(&cfg80211_mutex);
705 795
706 rdev = __cfg80211_rdev_from_info(info); 796 if (info->attrs[NL80211_ATTR_IFINDEX]) {
707 if (IS_ERR(rdev)) { 797 int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
708 mutex_unlock(&cfg80211_mutex); 798
709 result = PTR_ERR(rdev); 799 netdev = dev_get_by_index(genl_info_net(info), ifindex);
710 goto unlock; 800 if (netdev && netdev->ieee80211_ptr) {
801 rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy);
802 mutex_lock(&rdev->mtx);
803 } else
804 netdev = NULL;
711 } 805 }
712 806
713 mutex_lock(&rdev->mtx); 807 if (!netdev) {
808 rdev = __cfg80211_rdev_from_info(info);
809 if (IS_ERR(rdev)) {
810 mutex_unlock(&cfg80211_mutex);
811 result = PTR_ERR(rdev);
812 goto unlock;
813 }
814 wdev = NULL;
815 netdev = NULL;
816 result = 0;
817
818 mutex_lock(&rdev->mtx);
819 } else if (netif_running(netdev) &&
820 nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
821 wdev = netdev->ieee80211_ptr;
822 else
823 wdev = NULL;
824
825 /*
826 * end workaround code, by now the rdev is available
827 * and locked, and wdev may or may not be NULL.
828 */
714 829
715 if (info->attrs[NL80211_ATTR_WIPHY_NAME]) 830 if (info->attrs[NL80211_ATTR_WIPHY_NAME])
716 result = cfg80211_dev_rename( 831 result = cfg80211_dev_rename(
@@ -749,26 +864,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
749 } 864 }
750 865
751 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { 866 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
752 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; 867 result = __nl80211_set_channel(rdev, wdev, info);
753 u32 freq;
754
755 result = -EINVAL;
756
757 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
758 channel_type = nla_get_u32(info->attrs[
759 NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
760 if (channel_type != NL80211_CHAN_NO_HT &&
761 channel_type != NL80211_CHAN_HT20 &&
762 channel_type != NL80211_CHAN_HT40PLUS &&
763 channel_type != NL80211_CHAN_HT40MINUS)
764 goto bad_res;
765 }
766
767 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
768
769 mutex_lock(&rdev->devlist_mtx);
770 result = rdev_set_freq(rdev, NULL, freq, channel_type);
771 mutex_unlock(&rdev->devlist_mtx);
772 if (result) 868 if (result)
773 goto bad_res; 869 goto bad_res;
774 } 870 }
@@ -865,6 +961,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
865 961
866 bad_res: 962 bad_res:
867 mutex_unlock(&rdev->mtx); 963 mutex_unlock(&rdev->mtx);
964 if (netdev)
965 dev_put(netdev);
868 unlock: 966 unlock:
869 rtnl_unlock(); 967 rtnl_unlock();
870 return result; 968 return result;
@@ -3562,9 +3660,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
3562{ 3660{
3563 struct cfg80211_registered_device *rdev; 3661 struct cfg80211_registered_device *rdev;
3564 struct net_device *dev; 3662 struct net_device *dev;
3565 struct wireless_dev *wdev;
3566 struct cfg80211_crypto_settings crypto; 3663 struct cfg80211_crypto_settings crypto;
3567 struct ieee80211_channel *chan, *fixedchan; 3664 struct ieee80211_channel *chan;
3568 const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; 3665 const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
3569 int err, ssid_len, ie_len = 0; 3666 int err, ssid_len, ie_len = 0;
3570 bool use_mfp = false; 3667 bool use_mfp = false;
@@ -3607,16 +3704,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
3607 goto out; 3704 goto out;
3608 } 3705 }
3609 3706
3610 mutex_lock(&rdev->devlist_mtx);
3611 wdev = dev->ieee80211_ptr;
3612 fixedchan = rdev_fixed_channel(rdev, wdev);
3613 if (fixedchan && chan != fixedchan) {
3614 err = -EBUSY;
3615 mutex_unlock(&rdev->devlist_mtx);
3616 goto out;
3617 }
3618 mutex_unlock(&rdev->devlist_mtx);
3619
3620 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); 3707 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
3621 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); 3708 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
3622 3709
@@ -5186,6 +5273,12 @@ static struct genl_ops nl80211_ops[] = {
5186 .policy = nl80211_policy, 5273 .policy = nl80211_policy,
5187 .flags = GENL_ADMIN_PERM, 5274 .flags = GENL_ADMIN_PERM,
5188 }, 5275 },
5276 {
5277 .cmd = NL80211_CMD_SET_CHANNEL,
5278 .doit = nl80211_set_channel,
5279 .policy = nl80211_policy,
5280 .flags = GENL_ADMIN_PERM,
5281 },
5189}; 5282};
5190 5283
5191static struct genl_multicast_group nl80211_mlme_mcgrp = { 5284static struct genl_multicast_group nl80211_mlme_mcgrp = {
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 8ddf5ae0dd03..72222f0074db 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -741,7 +741,6 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
741 const u8 *prev_bssid) 741 const u8 *prev_bssid)
742{ 742{
743 struct wireless_dev *wdev = dev->ieee80211_ptr; 743 struct wireless_dev *wdev = dev->ieee80211_ptr;
744 struct ieee80211_channel *chan;
745 struct cfg80211_bss *bss = NULL; 744 struct cfg80211_bss *bss = NULL;
746 int err; 745 int err;
747 746
@@ -750,10 +749,6 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
750 if (wdev->sme_state != CFG80211_SME_IDLE) 749 if (wdev->sme_state != CFG80211_SME_IDLE)
751 return -EALREADY; 750 return -EALREADY;
752 751
753 chan = rdev_fixed_channel(rdev, wdev);
754 if (chan && chan != connect->channel)
755 return -EBUSY;
756
757 if (WARN_ON(wdev->connect_keys)) { 752 if (WARN_ON(wdev->connect_keys)) {
758 kfree(wdev->connect_keys); 753 kfree(wdev->connect_keys);
759 wdev->connect_keys = NULL; 754 wdev->connect_keys = NULL;
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index a60a2773b497..96342993cf93 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -782,16 +782,22 @@ int cfg80211_wext_siwfreq(struct net_device *dev,
782 return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra); 782 return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra);
783 case NL80211_IFTYPE_ADHOC: 783 case NL80211_IFTYPE_ADHOC:
784 return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra); 784 return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
785 default: 785 case NL80211_IFTYPE_MONITOR:
786 case NL80211_IFTYPE_WDS:
787 case NL80211_IFTYPE_MESH_POINT:
786 freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); 788 freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
787 if (freq < 0) 789 if (freq < 0)
788 return freq; 790 return freq;
789 if (freq == 0) 791 if (freq == 0)
790 return -EINVAL; 792 return -EINVAL;
793 wdev_lock(wdev);
791 mutex_lock(&rdev->devlist_mtx); 794 mutex_lock(&rdev->devlist_mtx);
792 err = rdev_set_freq(rdev, NULL, freq, NL80211_CHAN_NO_HT); 795 err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
793 mutex_unlock(&rdev->devlist_mtx); 796 mutex_unlock(&rdev->devlist_mtx);
797 wdev_unlock(wdev);
794 return err; 798 return err;
799 default:
800 return -EOPNOTSUPP;
795 } 801 }
796} 802}
797EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq); 803EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq);
@@ -801,7 +807,6 @@ int cfg80211_wext_giwfreq(struct net_device *dev,
801 struct iw_freq *freq, char *extra) 807 struct iw_freq *freq, char *extra)
802{ 808{
803 struct wireless_dev *wdev = dev->ieee80211_ptr; 809 struct wireless_dev *wdev = dev->ieee80211_ptr;
804 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
805 810
806 switch (wdev->iftype) { 811 switch (wdev->iftype) {
807 case NL80211_IFTYPE_STATION: 812 case NL80211_IFTYPE_STATION:
@@ -809,9 +814,9 @@ int cfg80211_wext_giwfreq(struct net_device *dev,
809 case NL80211_IFTYPE_ADHOC: 814 case NL80211_IFTYPE_ADHOC:
810 return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); 815 return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
811 default: 816 default:
812 if (!rdev->channel) 817 if (!wdev->channel)
813 return -EINVAL; 818 return -EINVAL;
814 freq->m = rdev->channel->center_freq; 819 freq->m = wdev->channel->center_freq;
815 freq->e = 6; 820 freq->e = 6;
816 return 0; 821 return 0;
817 } 822 }
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index d5c6140f4cb8..9818198add8a 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -108,7 +108,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
108 108
109 /* SSID is not set, we just want to switch channel */ 109 /* SSID is not set, we just want to switch channel */
110 if (chan && !wdev->wext.connect.ssid_len) { 110 if (chan && !wdev->wext.connect.ssid_len) {
111 err = rdev_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT); 111 err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
112 goto out; 112 goto out;
113 } 113 }
114 114