diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 13 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/main.c | 30 | ||||
-rw-r--r-- | net/mac80211/util.c | 1 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 57 |
5 files changed, 98 insertions, 4 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 16423f94801b..7a7a6c176dc5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1095,6 +1095,18 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, | |||
1095 | return 0; | 1095 | return 0; |
1096 | } | 1096 | } |
1097 | 1097 | ||
1098 | static int ieee80211_set_channel(struct wiphy *wiphy, | ||
1099 | struct ieee80211_channel *chan, | ||
1100 | enum nl80211_sec_chan_offset sec_chan_offset) | ||
1101 | { | ||
1102 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1103 | |||
1104 | local->oper_channel = chan; | ||
1105 | local->oper_sec_chan_offset = sec_chan_offset; | ||
1106 | |||
1107 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
1108 | } | ||
1109 | |||
1098 | struct cfg80211_ops mac80211_config_ops = { | 1110 | struct cfg80211_ops mac80211_config_ops = { |
1099 | .add_virtual_intf = ieee80211_add_iface, | 1111 | .add_virtual_intf = ieee80211_add_iface, |
1100 | .del_virtual_intf = ieee80211_del_iface, | 1112 | .del_virtual_intf = ieee80211_del_iface, |
@@ -1122,4 +1134,5 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1122 | #endif | 1134 | #endif |
1123 | .change_bss = ieee80211_change_bss, | 1135 | .change_bss = ieee80211_change_bss, |
1124 | .set_txq_params = ieee80211_set_txq_params, | 1136 | .set_txq_params = ieee80211_set_txq_params, |
1137 | .set_channel = ieee80211_set_channel, | ||
1125 | }; | 1138 | }; |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 155a20410017..527205f8c1a1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -626,6 +626,7 @@ struct ieee80211_local { | |||
626 | struct delayed_work scan_work; | 626 | struct delayed_work scan_work; |
627 | struct ieee80211_sub_if_data *scan_sdata; | 627 | struct ieee80211_sub_if_data *scan_sdata; |
628 | struct ieee80211_channel *oper_channel, *scan_channel; | 628 | struct ieee80211_channel *oper_channel, *scan_channel; |
629 | enum nl80211_sec_chan_offset oper_sec_chan_offset; | ||
629 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; | 630 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; |
630 | size_t scan_ssid_len; | 631 | size_t scan_ssid_len; |
631 | struct list_head bss_list; | 632 | struct list_head bss_list; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index cec9b6d3e1ce..29c3ecf7e914 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -195,20 +195,42 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
195 | struct ieee80211_channel *chan; | 195 | struct ieee80211_channel *chan; |
196 | int ret = 0; | 196 | int ret = 0; |
197 | int power; | 197 | int power; |
198 | enum nl80211_sec_chan_offset sec_chan_offset; | ||
198 | 199 | ||
199 | might_sleep(); | 200 | might_sleep(); |
200 | 201 | ||
201 | if (local->sw_scanning) | 202 | if (local->sw_scanning) { |
202 | chan = local->scan_channel; | 203 | chan = local->scan_channel; |
203 | else | 204 | sec_chan_offset = NL80211_SEC_CHAN_NO_HT; |
205 | } else { | ||
204 | chan = local->oper_channel; | 206 | chan = local->oper_channel; |
207 | sec_chan_offset = local->oper_sec_chan_offset; | ||
208 | } | ||
205 | 209 | ||
206 | if (chan != local->hw.conf.channel) { | 210 | if (chan != local->hw.conf.channel || |
211 | sec_chan_offset != local->hw.conf.ht.sec_chan_offset) { | ||
207 | local->hw.conf.channel = chan; | 212 | local->hw.conf.channel = chan; |
213 | switch (sec_chan_offset) { | ||
214 | case NL80211_SEC_CHAN_NO_HT: | ||
215 | local->hw.conf.ht.enabled = false; | ||
216 | local->hw.conf.ht.sec_chan_offset = 0; | ||
217 | break; | ||
218 | case NL80211_SEC_CHAN_DISABLED: | ||
219 | local->hw.conf.ht.enabled = true; | ||
220 | local->hw.conf.ht.sec_chan_offset = 0; | ||
221 | break; | ||
222 | case NL80211_SEC_CHAN_BELOW: | ||
223 | local->hw.conf.ht.enabled = true; | ||
224 | local->hw.conf.ht.sec_chan_offset = -1; | ||
225 | break; | ||
226 | case NL80211_SEC_CHAN_ABOVE: | ||
227 | local->hw.conf.ht.enabled = true; | ||
228 | local->hw.conf.ht.sec_chan_offset = 1; | ||
229 | break; | ||
230 | } | ||
208 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; | 231 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; |
209 | } | 232 | } |
210 | 233 | ||
211 | |||
212 | if (!local->hw.conf.power_level) | 234 | if (!local->hw.conf.power_level) |
213 | power = chan->max_power; | 235 | power = chan->max_power; |
214 | else | 236 | else |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0f841317c7e9..505d68f344ce 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -641,6 +641,7 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz) | |||
641 | chan->flags & IEEE80211_CHAN_NO_IBSS) | 641 | chan->flags & IEEE80211_CHAN_NO_IBSS) |
642 | return ret; | 642 | return ret; |
643 | local->oper_channel = chan; | 643 | local->oper_channel = chan; |
644 | local->oper_sec_chan_offset = NL80211_SEC_CHAN_NO_HT; | ||
644 | 645 | ||
645 | if (local->sw_scanning || local->hw_scanning) | 646 | if (local->sw_scanning || local->hw_scanning) |
646 | ret = 0; | 647 | ret = 0; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c9141e3df9ba..9caee6022e3f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -59,6 +59,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
59 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, | 59 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, |
60 | .len = BUS_ID_SIZE-1 }, | 60 | .len = BUS_ID_SIZE-1 }, |
61 | [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, | 61 | [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, |
62 | [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, | ||
63 | [NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET] = { .type = NLA_U32 }, | ||
62 | 64 | ||
63 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, | 65 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, |
64 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, | 66 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, |
@@ -359,6 +361,61 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
359 | } | 361 | } |
360 | } | 362 | } |
361 | 363 | ||
364 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
365 | enum nl80211_sec_chan_offset sec_chan_offset = | ||
366 | NL80211_SEC_CHAN_NO_HT; | ||
367 | struct ieee80211_channel *chan; | ||
368 | u32 freq, sec_freq; | ||
369 | |||
370 | if (!rdev->ops->set_channel) { | ||
371 | result = -EOPNOTSUPP; | ||
372 | goto bad_res; | ||
373 | } | ||
374 | |||
375 | if (info->attrs[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]) { | ||
376 | sec_chan_offset = nla_get_u32( | ||
377 | info->attrs[ | ||
378 | NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]); | ||
379 | if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT && | ||
380 | sec_chan_offset != NL80211_SEC_CHAN_DISABLED && | ||
381 | sec_chan_offset != NL80211_SEC_CHAN_BELOW && | ||
382 | sec_chan_offset != NL80211_SEC_CHAN_ABOVE) { | ||
383 | result = -EINVAL; | ||
384 | goto bad_res; | ||
385 | } | ||
386 | } | ||
387 | |||
388 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | ||
389 | chan = ieee80211_get_channel(&rdev->wiphy, freq); | ||
390 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) { | ||
391 | /* Primary channel not allowed */ | ||
392 | result = -EINVAL; | ||
393 | goto bad_res; | ||
394 | } | ||
395 | if (sec_chan_offset == NL80211_SEC_CHAN_BELOW) | ||
396 | sec_freq = freq - 20; | ||
397 | else if (sec_chan_offset == NL80211_SEC_CHAN_ABOVE) | ||
398 | sec_freq = freq + 20; | ||
399 | else | ||
400 | sec_freq = 0; | ||
401 | |||
402 | if (sec_freq) { | ||
403 | struct ieee80211_channel *schan; | ||
404 | schan = ieee80211_get_channel(&rdev->wiphy, sec_freq); | ||
405 | if (!schan || schan->flags & IEEE80211_CHAN_DISABLED) { | ||
406 | /* Secondary channel not allowed */ | ||
407 | result = -EINVAL; | ||
408 | goto bad_res; | ||
409 | } | ||
410 | } | ||
411 | |||
412 | result = rdev->ops->set_channel(&rdev->wiphy, chan, | ||
413 | sec_chan_offset); | ||
414 | if (result) | ||
415 | goto bad_res; | ||
416 | } | ||
417 | |||
418 | |||
362 | bad_res: | 419 | bad_res: |
363 | cfg80211_put_dev(rdev); | 420 | cfg80211_put_dev(rdev); |
364 | return result; | 421 | return result; |