aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2012-06-12 14:25:04 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-06-12 14:25:04 -0400
commit0440507bbc44149e63bbfb9df730ba3820371904 (patch)
tree7275e41aa1aa7e4d19d0503f1c15f07991c1a120 /net/wireless/nl80211.c
parent8d242488ce4627dd7e6333caab56df11ea25e239 (diff)
parent7f0d9f430dc99303558adc30a75eef10c43f7bec (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c129
1 files changed, 106 insertions, 23 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 206465dc0cab..7ae54b82291f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -921,7 +921,12 @@ 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_monitor_channel || dev->ops->start_ap ||
925 dev->ops->join_mesh) {
926 i++;
927 if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
928 goto nla_put_failure;
929 }
925 CMD(set_wds_peer, SET_WDS_PEER); 930 CMD(set_wds_peer, SET_WDS_PEER);
926 if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { 931 if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
927 CMD(tdls_mgmt, TDLS_MGMT); 932 CMD(tdls_mgmt, TDLS_MGMT);
@@ -1162,18 +1167,22 @@ static int parse_txq_params(struct nlattr *tb[],
1162static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) 1167static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
1163{ 1168{
1164 /* 1169 /*
1165 * You can only set the channel explicitly for AP, mesh 1170 * You can only set the channel explicitly for WDS interfaces,
1166 * and WDS type interfaces; all others have their channel 1171 * all others have their channel managed via their respective
1167 * managed via their respective "establish a connection" 1172 * "establish a connection" command (connect, join, ...)
1168 * command (connect, join, ...) 1173 *
1174 * For AP/GO and mesh mode, the channel can be set with the
1175 * channel userspace API, but is only stored and passed to the
1176 * low-level driver when the AP starts or the mesh is joined.
1177 * This is for backward compatibility, userspace can also give
1178 * the channel in the start-ap or join-mesh commands instead.
1169 * 1179 *
1170 * Monitors are special as they are normally slaved to 1180 * Monitors are special as they are normally slaved to
1171 * whatever else is going on, so they behave as though 1181 * whatever else is going on, so they have their own special
1172 * you tried setting the wiphy channel itself. 1182 * operation to set the monitor channel if possible.
1173 */ 1183 */
1174 return !wdev || 1184 return !wdev ||
1175 wdev->iftype == NL80211_IFTYPE_AP || 1185 wdev->iftype == NL80211_IFTYPE_AP ||
1176 wdev->iftype == NL80211_IFTYPE_WDS ||
1177 wdev->iftype == NL80211_IFTYPE_MESH_POINT || 1186 wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
1178 wdev->iftype == NL80211_IFTYPE_MONITOR || 1187 wdev->iftype == NL80211_IFTYPE_MONITOR ||
1179 wdev->iftype == NL80211_IFTYPE_P2P_GO; 1188 wdev->iftype == NL80211_IFTYPE_P2P_GO;
@@ -1204,9 +1213,14 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
1204 struct wireless_dev *wdev, 1213 struct wireless_dev *wdev,
1205 struct genl_info *info) 1214 struct genl_info *info)
1206{ 1215{
1216 struct ieee80211_channel *channel;
1207 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; 1217 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
1208 u32 freq; 1218 u32 freq;
1209 int result; 1219 int result;
1220 enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
1221
1222 if (wdev)
1223 iftype = wdev->iftype;
1210 1224
1211 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) 1225 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
1212 return -EINVAL; 1226 return -EINVAL;
@@ -1221,12 +1235,32 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
1221 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); 1235 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
1222 1236
1223 mutex_lock(&rdev->devlist_mtx); 1237 mutex_lock(&rdev->devlist_mtx);
1224 if (wdev) { 1238 switch (iftype) {
1225 wdev_lock(wdev); 1239 case NL80211_IFTYPE_AP:
1226 result = cfg80211_set_freq(rdev, wdev, freq, channel_type); 1240 case NL80211_IFTYPE_P2P_GO:
1227 wdev_unlock(wdev); 1241 if (wdev->beacon_interval) {
1228 } else { 1242 result = -EBUSY;
1229 result = cfg80211_set_freq(rdev, NULL, freq, channel_type); 1243 break;
1244 }
1245 channel = rdev_freq_to_chan(rdev, freq, channel_type);
1246 if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
1247 channel,
1248 channel_type)) {
1249 result = -EINVAL;
1250 break;
1251 }
1252 wdev->preset_chan = channel;
1253 wdev->preset_chantype = channel_type;
1254 result = 0;
1255 break;
1256 case NL80211_IFTYPE_MESH_POINT:
1257 result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type);
1258 break;
1259 case NL80211_IFTYPE_MONITOR:
1260 result = cfg80211_set_monitor_channel(rdev, freq, channel_type);
1261 break;
1262 default:
1263 result = -EINVAL;
1230 } 1264 }
1231 mutex_unlock(&rdev->devlist_mtx); 1265 mutex_unlock(&rdev->devlist_mtx);
1232 1266
@@ -1310,8 +1344,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
1310 result = 0; 1344 result = 0;
1311 1345
1312 mutex_lock(&rdev->mtx); 1346 mutex_lock(&rdev->mtx);
1313 } else if (netif_running(netdev) && 1347 } else if (nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
1314 nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
1315 wdev = netdev->ieee80211_ptr; 1348 wdev = netdev->ieee80211_ptr;
1316 else 1349 else
1317 wdev = NULL; 1350 wdev = NULL;
@@ -2299,6 +2332,29 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
2299 info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]); 2332 info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
2300 } 2333 }
2301 2334
2335 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
2336 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
2337
2338 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
2339 !nl80211_valid_channel_type(info, &channel_type))
2340 return -EINVAL;
2341
2342 params.channel = rdev_freq_to_chan(rdev,
2343 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
2344 channel_type);
2345 if (!params.channel)
2346 return -EINVAL;
2347 params.channel_type = channel_type;
2348 } else if (wdev->preset_chan) {
2349 params.channel = wdev->preset_chan;
2350 params.channel_type = wdev->preset_chantype;
2351 } else
2352 return -EINVAL;
2353
2354 if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel,
2355 params.channel_type))
2356 return -EINVAL;
2357
2302 err = rdev->ops->start_ap(&rdev->wiphy, dev, &params); 2358 err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
2303 if (!err) 2359 if (!err)
2304 wdev->beacon_interval = params.beacon_interval; 2360 wdev->beacon_interval = params.beacon_interval;
@@ -5489,18 +5545,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
5489 5545
5490 duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); 5546 duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
5491 5547
5548 if (!rdev->ops->remain_on_channel ||
5549 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
5550 return -EOPNOTSUPP;
5551
5492 /* 5552 /*
5493 * We should be on that channel for at least one jiffie, 5553 * We should be on that channel for at least a minimum amount of
5494 * and more than 5 seconds seems excessive. 5554 * time (10ms) but no longer than the driver supports.
5495 */ 5555 */
5496 if (!duration || !msecs_to_jiffies(duration) || 5556 if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
5497 duration > rdev->wiphy.max_remain_on_channel_duration) 5557 duration > rdev->wiphy.max_remain_on_channel_duration)
5498 return -EINVAL; 5558 return -EINVAL;
5499 5559
5500 if (!rdev->ops->remain_on_channel ||
5501 !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
5502 return -EOPNOTSUPP;
5503
5504 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && 5560 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
5505 !nl80211_valid_channel_type(info, &channel_type)) 5561 !nl80211_valid_channel_type(info, &channel_type))
5506 return -EINVAL; 5562 return -EINVAL;
@@ -5771,6 +5827,15 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
5771 if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) 5827 if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
5772 return -EINVAL; 5828 return -EINVAL;
5773 wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); 5829 wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
5830
5831 /*
5832 * We should wait on the channel for at least a minimum amount
5833 * of time (10ms) but no longer than the driver supports.
5834 */
5835 if (wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
5836 wait > rdev->wiphy.max_remain_on_channel_duration)
5837 return -EINVAL;
5838
5774 } 5839 }
5775 5840
5776 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { 5841 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
@@ -6032,6 +6097,24 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
6032 return err; 6097 return err;
6033 } 6098 }
6034 6099
6100 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
6101 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
6102
6103 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
6104 !nl80211_valid_channel_type(info, &channel_type))
6105 return -EINVAL;
6106
6107 setup.channel = rdev_freq_to_chan(rdev,
6108 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
6109 channel_type);
6110 if (!setup.channel)
6111 return -EINVAL;
6112 setup.channel_type = channel_type;
6113 } else {
6114 /* cfg80211_join_mesh() will sort it out */
6115 setup.channel = NULL;
6116 }
6117
6035 return cfg80211_join_mesh(rdev, dev, &setup, &cfg); 6118 return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
6036} 6119}
6037 6120