diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-05-16 17:50:18 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-06-05 15:32:16 -0400 |
commit | aa430da41019c1694f6a8e3b8bef1d12ed52b0ad (patch) | |
tree | 086b60a5c6253cad2c78f5a976d0608f375f2b03 /net/wireless/nl80211.c | |
parent | d58e7e37aac0465b08527adadc8016421bd4060e (diff) |
cfg80211: provide channel to start_ap function
Instead of setting the channel first and then
starting the AP, let cfg80211 store the channel
and provide it as one of the AP settings.
This means that now you have to set the channel
before you can start an AP interface, but since
hostapd/wpa_supplicant always do that we're OK
with this change.
Alternatively, it's now possible to give the
channel as an attribute to the start-ap nl80211
command, overriding any preset channel.
Cc: Kalle Valo <kvalo@qca.qualcomm.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 53 |
1 files changed, 51 insertions, 2 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 206465dc0cab..74f4a8f93935 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -921,7 +921,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
921 | if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS)) | 921 | if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS)) |
922 | goto nla_put_failure; | 922 | goto nla_put_failure; |
923 | } | 923 | } |
924 | CMD(set_channel, SET_CHANNEL); | 924 | if (dev->ops->set_channel || dev->ops->start_ap) { |
925 | i++; | ||
926 | if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL)) | ||
927 | goto nla_put_failure; | ||
928 | } | ||
925 | CMD(set_wds_peer, SET_WDS_PEER); | 929 | CMD(set_wds_peer, SET_WDS_PEER); |
926 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { | 930 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { |
927 | CMD(tdls_mgmt, TDLS_MGMT); | 931 | CMD(tdls_mgmt, TDLS_MGMT); |
@@ -1170,6 +1174,9 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) | |||
1170 | * Monitors are special as they are normally slaved to | 1174 | * Monitors are special as they are normally slaved to |
1171 | * whatever else is going on, so they behave as though | 1175 | * whatever else is going on, so they behave as though |
1172 | * you tried setting the wiphy channel itself. | 1176 | * you tried setting the wiphy channel itself. |
1177 | * | ||
1178 | * For AP/GO modes, it's only for compatibility, you can | ||
1179 | * also give the channel to the start-AP command. | ||
1173 | */ | 1180 | */ |
1174 | return !wdev || | 1181 | return !wdev || |
1175 | wdev->iftype == NL80211_IFTYPE_AP || | 1182 | wdev->iftype == NL80211_IFTYPE_AP || |
@@ -1204,6 +1211,7 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
1204 | struct wireless_dev *wdev, | 1211 | struct wireless_dev *wdev, |
1205 | struct genl_info *info) | 1212 | struct genl_info *info) |
1206 | { | 1213 | { |
1214 | struct ieee80211_channel *channel; | ||
1207 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 1215 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
1208 | u32 freq; | 1216 | u32 freq; |
1209 | int result; | 1217 | int result; |
@@ -1221,7 +1229,25 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
1221 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 1229 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
1222 | 1230 | ||
1223 | mutex_lock(&rdev->devlist_mtx); | 1231 | mutex_lock(&rdev->devlist_mtx); |
1224 | if (wdev) { | 1232 | if (wdev) switch (wdev->iftype) { |
1233 | case NL80211_IFTYPE_AP: | ||
1234 | case NL80211_IFTYPE_P2P_GO: | ||
1235 | if (wdev->beacon_interval) { | ||
1236 | result = -EBUSY; | ||
1237 | break; | ||
1238 | } | ||
1239 | channel = rdev_freq_to_chan(rdev, freq, channel_type); | ||
1240 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, | ||
1241 | channel, | ||
1242 | channel_type)) { | ||
1243 | result = -EINVAL; | ||
1244 | break; | ||
1245 | } | ||
1246 | wdev->preset_chan = channel; | ||
1247 | wdev->preset_chantype = channel_type; | ||
1248 | result = 0; | ||
1249 | break; | ||
1250 | default: | ||
1225 | wdev_lock(wdev); | 1251 | wdev_lock(wdev); |
1226 | result = cfg80211_set_freq(rdev, wdev, freq, channel_type); | 1252 | result = cfg80211_set_freq(rdev, wdev, freq, channel_type); |
1227 | wdev_unlock(wdev); | 1253 | wdev_unlock(wdev); |
@@ -2299,6 +2325,29 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
2299 | info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]); | 2325 | info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]); |
2300 | } | 2326 | } |
2301 | 2327 | ||
2328 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
2329 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||
2330 | |||
2331 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && | ||
2332 | !nl80211_valid_channel_type(info, &channel_type)) | ||
2333 | return -EINVAL; | ||
2334 | |||
2335 | params.channel = rdev_freq_to_chan(rdev, | ||
2336 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), | ||
2337 | channel_type); | ||
2338 | if (!params.channel) | ||
2339 | return -EINVAL; | ||
2340 | params.channel_type = channel_type; | ||
2341 | } else if (wdev->preset_chan) { | ||
2342 | params.channel = wdev->preset_chan; | ||
2343 | params.channel_type = wdev->preset_chantype; | ||
2344 | } else | ||
2345 | return -EINVAL; | ||
2346 | |||
2347 | if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel, | ||
2348 | params.channel_type)) | ||
2349 | return -EINVAL; | ||
2350 | |||
2302 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); | 2351 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); |
2303 | if (!err) | 2352 | if (!err) |
2304 | wdev->beacon_interval = params.beacon_interval; | 2353 | wdev->beacon_interval = params.beacon_interval; |