|
@@ -44,6 +44,38 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
|
|
|
return chan;
|
|
|
}
|
|
|
|
|
|
+static bool can_beacon_sec_chan(struct wiphy *wiphy,
|
|
|
+ struct ieee80211_channel *chan,
|
|
|
+ enum nl80211_channel_type channel_type)
|
|
|
+{
|
|
|
+ struct ieee80211_channel *sec_chan;
|
|
|
+ int diff;
|
|
|
+
|
|
|
+ switch (channel_type) {
|
|
|
+ case NL80211_CHAN_HT40PLUS:
|
|
|
+ diff = 20;
|
|
|
+ break;
|
|
|
+ case NL80211_CHAN_HT40MINUS:
|
|
|
+ diff = -20;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff);
|
|
|
+ if (!sec_chan)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /* we'll need a DFS capability later */
|
|
|
+ if (sec_chan->flags & (IEEE80211_CHAN_DISABLED |
|
|
|
+ IEEE80211_CHAN_PASSIVE_SCAN |
|
|
|
+ IEEE80211_CHAN_NO_IBSS |
|
|
|
+ IEEE80211_CHAN_RADAR))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
|
|
|
struct wireless_dev *wdev, int freq,
|
|
|
enum nl80211_channel_type channel_type)
|
|
@@ -68,6 +100,28 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
|
|
|
if (!chan)
|
|
|
return -EINVAL;
|
|
|
|
|
|
+ /* Both channels should be able to initiate communication */
|
|
|
+ if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC ||
|
|
|
+ wdev->iftype == NL80211_IFTYPE_AP ||
|
|
|
+ wdev->iftype == NL80211_IFTYPE_AP_VLAN ||
|
|
|
+ wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
|
|
|
+ wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
|
|
|
+ switch (channel_type) {
|
|
|
+ case NL80211_CHAN_HT40PLUS:
|
|
|
+ case NL80211_CHAN_HT40MINUS:
|
|
|
+ if (!can_beacon_sec_chan(&rdev->wiphy, chan,
|
|
|
+ channel_type)) {
|
|
|
+ printk(KERN_DEBUG
|
|
|
+ "cfg80211: Secondary channel not "
|
|
|
+ "allowed to initiate communication\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
result = rdev->ops->set_channel(&rdev->wiphy,
|
|
|
wdev ? wdev->netdev : NULL,
|
|
|
chan, channel_type);
|