aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorSimon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de>2013-01-08 08:04:07 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-01-16 17:41:54 -0500
commit11c4a075db2f8774d37544342c8cb9752b4db9e1 (patch)
treedbd28f1bbac2a42ebe4aade8d1a4bc2871431924 /net/wireless
parentcee00a959c0a86571e6f99cf42f0261d7e54d2ae (diff)
cfg80211: check radar interface combinations
To ease further DFS development regarding interface combinations, use the interface combinations structure to test for radar capabilities. Drivers can specify which channel widths they support, and in which modes. Right now only a single AP interface is allowed, but as the DFS code evolves other combinations can be enabled. Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/core.c12
-rw-r--r--net/wireless/core.h7
-rw-r--r--net/wireless/nl80211.c3
-rw-r--r--net/wireless/util.c41
4 files changed, 55 insertions, 8 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 747dd9365a44..0e702cdc6043 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -382,8 +382,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
382 382
383 c = &wiphy->iface_combinations[i]; 383 c = &wiphy->iface_combinations[i];
384 384
385 /* Combinations with just one interface aren't real */ 385 /*
386 if (WARN_ON(c->max_interfaces < 2)) 386 * Combinations with just one interface aren't real,
387 * however we make an exception for DFS.
388 */
389 if (WARN_ON((c->max_interfaces < 2) && !c->radar_detect_widths))
387 return -EINVAL; 390 return -EINVAL;
388 391
389 /* Need at least one channel */ 392 /* Need at least one channel */
@@ -398,6 +401,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
398 CFG80211_MAX_NUM_DIFFERENT_CHANNELS)) 401 CFG80211_MAX_NUM_DIFFERENT_CHANNELS))
399 return -EINVAL; 402 return -EINVAL;
400 403
404 /* DFS only works on one channel. */
405 if (WARN_ON(c->radar_detect_widths &&
406 (c->num_different_channels > 1)))
407 return -EINVAL;
408
401 if (WARN_ON(!c->n_limits)) 409 if (WARN_ON(!c->n_limits))
402 return -EINVAL; 410 return -EINVAL;
403 411
diff --git a/net/wireless/core.h b/net/wireless/core.h
index f342267e3620..8396f7671c8d 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -425,7 +425,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
425 struct wireless_dev *wdev, 425 struct wireless_dev *wdev,
426 enum nl80211_iftype iftype, 426 enum nl80211_iftype iftype,
427 struct ieee80211_channel *chan, 427 struct ieee80211_channel *chan,
428 enum cfg80211_chan_mode chanmode); 428 enum cfg80211_chan_mode chanmode,
429 u8 radar_detect);
429 430
430static inline int 431static inline int
431cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, 432cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
@@ -433,7 +434,7 @@ cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
433 enum nl80211_iftype iftype) 434 enum nl80211_iftype iftype)
434{ 435{
435 return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL, 436 return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL,
436 CHAN_MODE_UNDEFINED); 437 CHAN_MODE_UNDEFINED, 0);
437} 438}
438 439
439static inline int 440static inline int
@@ -450,7 +451,7 @@ cfg80211_can_use_chan(struct cfg80211_registered_device *rdev,
450 enum cfg80211_chan_mode chanmode) 451 enum cfg80211_chan_mode chanmode)
451{ 452{
452 return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, 453 return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
453 chan, chanmode); 454 chan, chanmode, 0);
454} 455}
455 456
456void 457void
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index df82a5c9faee..33de80364c5c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -856,6 +856,9 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy,
856 nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM, 856 nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
857 c->max_interfaces)) 857 c->max_interfaces))
858 goto nla_put_failure; 858 goto nla_put_failure;
859 if (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
860 c->radar_detect_widths))
861 goto nla_put_failure;
859 862
860 nla_nest_end(msg, nl_combi); 863 nla_nest_end(msg, nl_combi);
861 } 864 }
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 16d76a807c2f..1c2795d52db0 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1184,7 +1184,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
1184 struct wireless_dev *wdev, 1184 struct wireless_dev *wdev,
1185 enum nl80211_iftype iftype, 1185 enum nl80211_iftype iftype,
1186 struct ieee80211_channel *chan, 1186 struct ieee80211_channel *chan,
1187 enum cfg80211_chan_mode chanmode) 1187 enum cfg80211_chan_mode chanmode,
1188 u8 radar_detect)
1188{ 1189{
1189 struct wireless_dev *wdev_iter; 1190 struct wireless_dev *wdev_iter;
1190 u32 used_iftypes = BIT(iftype); 1191 u32 used_iftypes = BIT(iftype);
@@ -1195,14 +1196,45 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
1195 enum cfg80211_chan_mode chmode; 1196 enum cfg80211_chan_mode chmode;
1196 int num_different_channels = 0; 1197 int num_different_channels = 0;
1197 int total = 1; 1198 int total = 1;
1199 bool radar_required;
1198 int i, j; 1200 int i, j;
1199 1201
1200 ASSERT_RTNL(); 1202 ASSERT_RTNL();
1201 lockdep_assert_held(&rdev->devlist_mtx); 1203 lockdep_assert_held(&rdev->devlist_mtx);
1202 1204
1205 if (WARN_ON(hweight32(radar_detect) > 1))
1206 return -EINVAL;
1207
1208 switch (iftype) {
1209 case NL80211_IFTYPE_ADHOC:
1210 case NL80211_IFTYPE_AP:
1211 case NL80211_IFTYPE_AP_VLAN:
1212 case NL80211_IFTYPE_MESH_POINT:
1213 case NL80211_IFTYPE_P2P_GO:
1214 case NL80211_IFTYPE_WDS:
1215 radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR);
1216 break;
1217 case NL80211_IFTYPE_P2P_CLIENT:
1218 case NL80211_IFTYPE_STATION:
1219 case NL80211_IFTYPE_MONITOR:
1220 radar_required = false;
1221 break;
1222 case NL80211_IFTYPE_P2P_DEVICE:
1223 case NUM_NL80211_IFTYPES:
1224 case NL80211_IFTYPE_UNSPECIFIED:
1225 default:
1226 return -EINVAL;
1227 }
1228
1229 if (radar_required && !radar_detect)
1230 return -EINVAL;
1231
1203 /* Always allow software iftypes */ 1232 /* Always allow software iftypes */
1204 if (rdev->wiphy.software_iftypes & BIT(iftype)) 1233 if (rdev->wiphy.software_iftypes & BIT(iftype)) {
1234 if (radar_detect)
1235 return -EINVAL;
1205 return 0; 1236 return 0;
1237 }
1206 1238
1207 memset(num, 0, sizeof(num)); 1239 memset(num, 0, sizeof(num));
1208 memset(used_channels, 0, sizeof(used_channels)); 1240 memset(used_channels, 0, sizeof(used_channels));
@@ -1275,7 +1307,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
1275 used_iftypes |= BIT(wdev_iter->iftype); 1307 used_iftypes |= BIT(wdev_iter->iftype);
1276 } 1308 }
1277 1309
1278 if (total == 1) 1310 if (total == 1 && !radar_detect)
1279 return 0; 1311 return 0;
1280 1312
1281 for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) { 1313 for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
@@ -1308,6 +1340,9 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
1308 } 1340 }
1309 } 1341 }
1310 1342
1343 if (radar_detect && !(c->radar_detect_widths & radar_detect))
1344 goto cont;
1345
1311 /* 1346 /*
1312 * Finally check that all iftypes that we're currently 1347 * Finally check that all iftypes that we're currently
1313 * using are actually part of this combination. If they 1348 * using are actually part of this combination. If they