aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de>2013-10-07 12:41:05 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-10-28 10:05:21 -0400
commit5336fa88e8ac6b666a3db9902a4797d94d86a702 (patch)
tree0dacc5508f7ab1e65f894d6f09c4b56e7a6da9fb
parent687da132234feb70748df04a007bc1820f392254 (diff)
nl80211/cfg80211: enable DFS for IBSS mode
To use DFS in IBSS mode, userspace is required to react to radar events. It can inform nl80211 that it is capable of doing so by adding a NL80211_ATTR_HANDLE_DFS attribute when joining the IBSS. This attribute is supplied to let the kernelspace know that the userspace application can and will handle radar events, e.g. by intiating channel switches to a valid channel. DFS channels may only be used if this attribute is supplied and the driver supports it. Driver support will be checked even if a channel without DFS will be initially joined, as a DFS channel may be chosen later. Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de> [fix attribute name in commit message] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/net/cfg80211.h6
-rw-r--r--include/uapi/linux/nl80211.h9
-rw-r--r--net/wireless/chan.c3
-rw-r--r--net/wireless/ibss.c24
-rw-r--r--net/wireless/nl80211.c8
-rw-r--r--net/wireless/util.c14
6 files changed, 53 insertions, 11 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 5db5fe24eff6..b1acf36e5f45 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1664,6 +1664,9 @@ struct cfg80211_disassoc_request {
1664 * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is 1664 * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
1665 * required to assume that the port is unauthorized until authorized by 1665 * required to assume that the port is unauthorized until authorized by
1666 * user space. Otherwise, port is marked authorized by default. 1666 * user space. Otherwise, port is marked authorized by default.
1667 * @userspace_handles_dfs: whether user space controls DFS operation, i.e.
1668 * changes the channel when a radar is detected. This is required
1669 * to operate on DFS channels.
1667 * @basic_rates: bitmap of basic rates to use when creating the IBSS 1670 * @basic_rates: bitmap of basic rates to use when creating the IBSS
1668 * @mcast_rate: per-band multicast rate index + 1 (0: disabled) 1671 * @mcast_rate: per-band multicast rate index + 1 (0: disabled)
1669 * @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask 1672 * @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask
@@ -1681,6 +1684,7 @@ struct cfg80211_ibss_params {
1681 bool channel_fixed; 1684 bool channel_fixed;
1682 bool privacy; 1685 bool privacy;
1683 bool control_port; 1686 bool control_port;
1687 bool userspace_handles_dfs;
1684 int mcast_rate[IEEE80211_NUM_BANDS]; 1688 int mcast_rate[IEEE80211_NUM_BANDS];
1685 struct ieee80211_ht_cap ht_capa; 1689 struct ieee80211_ht_cap ht_capa;
1686 struct ieee80211_ht_cap ht_capa_mask; 1690 struct ieee80211_ht_cap ht_capa_mask;
@@ -3061,6 +3065,7 @@ struct cfg80211_cached_keys;
3061 * @conn: (private) cfg80211 software SME connection state machine data 3065 * @conn: (private) cfg80211 software SME connection state machine data
3062 * @connect_keys: (private) keys to set after connection is established 3066 * @connect_keys: (private) keys to set after connection is established
3063 * @ibss_fixed: (private) IBSS is using fixed BSSID 3067 * @ibss_fixed: (private) IBSS is using fixed BSSID
3068 * @ibss_dfs_possible: (private) IBSS may change to a DFS channel
3064 * @event_list: (private) list for internal event processing 3069 * @event_list: (private) list for internal event processing
3065 * @event_lock: (private) lock for event list 3070 * @event_lock: (private) lock for event list
3066 */ 3071 */
@@ -3099,6 +3104,7 @@ struct wireless_dev {
3099 struct ieee80211_channel *channel; 3104 struct ieee80211_channel *channel;
3100 3105
3101 bool ibss_fixed; 3106 bool ibss_fixed;
3107 bool ibss_dfs_possible;
3102 3108
3103 bool ps; 3109 bool ps;
3104 int ps_timeout; 3110 int ps_timeout;
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index f2aef2a7a570..f752e9821e71 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1501,6 +1501,13 @@ enum nl80211_commands {
1501 * @NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES: array of supported 1501 * @NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES: array of supported
1502 * supported operating classes. 1502 * supported operating classes.
1503 * 1503 *
1504 * @NL80211_ATTR_HANDLE_DFS: A flag indicating whether user space
1505 * controls DFS operation in IBSS mode. If the flag is included in
1506 * %NL80211_CMD_JOIN_IBSS request, the driver will allow use of DFS
1507 * channels and reports radar events to userspace. Userspace is required
1508 * to react to radar events, e.g. initiate a channel switch or leave the
1509 * IBSS network.
1510 *
1504 * @NL80211_ATTR_MAX: highest attribute number currently defined 1511 * @NL80211_ATTR_MAX: highest attribute number currently defined
1505 * @__NL80211_ATTR_AFTER_LAST: internal use 1512 * @__NL80211_ATTR_AFTER_LAST: internal use
1506 */ 1513 */
@@ -1815,6 +1822,8 @@ enum nl80211_attrs {
1815 1822
1816 NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES, 1823 NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
1817 1824
1825 NL80211_ATTR_HANDLE_DFS,
1826
1818 /* add attributes here, update the policy in nl80211.c */ 1827 /* add attributes here, update the policy in nl80211.c */
1819 1828
1820 __NL80211_ATTR_AFTER_LAST, 1829 __NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 16f3c3a7b2c1..9b8cc877eb19 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -504,7 +504,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
504 case NL80211_IFTYPE_ADHOC: 504 case NL80211_IFTYPE_ADHOC:
505 if (wdev->current_bss) { 505 if (wdev->current_bss) {
506 *chan = wdev->current_bss->pub.channel; 506 *chan = wdev->current_bss->pub.channel;
507 *chanmode = wdev->ibss_fixed 507 *chanmode = (wdev->ibss_fixed &&
508 !wdev->ibss_dfs_possible)
508 ? CHAN_MODE_SHARED 509 ? CHAN_MODE_SHARED
509 : CHAN_MODE_EXCLUSIVE; 510 : CHAN_MODE_EXCLUSIVE;
510 return; 511 return;
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 39bff7d36768..fa7461b6ba39 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -83,6 +83,8 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
83 struct cfg80211_cached_keys *connkeys) 83 struct cfg80211_cached_keys *connkeys)
84{ 84{
85 struct wireless_dev *wdev = dev->ieee80211_ptr; 85 struct wireless_dev *wdev = dev->ieee80211_ptr;
86 struct ieee80211_channel *check_chan;
87 u8 radar_detect_width = 0;
86 int err; 88 int err;
87 89
88 ASSERT_WDEV_LOCK(wdev); 90 ASSERT_WDEV_LOCK(wdev);
@@ -114,14 +116,28 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
114 wdev->connect_keys = connkeys; 116 wdev->connect_keys = connkeys;
115 117
116 wdev->ibss_fixed = params->channel_fixed; 118 wdev->ibss_fixed = params->channel_fixed;
119 wdev->ibss_dfs_possible = params->userspace_handles_dfs;
117#ifdef CONFIG_CFG80211_WEXT 120#ifdef CONFIG_CFG80211_WEXT
118 wdev->wext.ibss.chandef = params->chandef; 121 wdev->wext.ibss.chandef = params->chandef;
119#endif 122#endif
123 check_chan = params->chandef.chan;
124 if (params->userspace_handles_dfs) {
125 /* use channel NULL to check for radar even if the current
126 * channel is not a radar channel - it might decide to change
127 * to DFS channel later.
128 */
129 radar_detect_width = BIT(params->chandef.width);
130 check_chan = NULL;
131 }
132
133 err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
134 check_chan,
135 (params->channel_fixed &&
136 !radar_detect_width)
137 ? CHAN_MODE_SHARED
138 : CHAN_MODE_EXCLUSIVE,
139 radar_detect_width);
120 140
121 err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan,
122 params->channel_fixed
123 ? CHAN_MODE_SHARED
124 : CHAN_MODE_EXCLUSIVE);
125 if (err) { 141 if (err) {
126 wdev->connect_keys = NULL; 142 wdev->connect_keys = NULL;
127 return err; 143 return err;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 460638ac2d73..7502d33a3a70 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -356,6 +356,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
356 [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_U16 }, 356 [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_U16 },
357 [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY }, 357 [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY },
358 [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY }, 358 [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY },
359 [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
359}; 360};
360 361
361/* policy for the key attributes */ 362/* policy for the key attributes */
@@ -5768,9 +5769,9 @@ skip_beacons:
5768 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef)) 5769 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
5769 return -EINVAL; 5770 return -EINVAL;
5770 5771
5771 /* DFS channels are only supported for AP/P2P GO ... for now. */
5772 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP || 5772 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP ||
5773 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) { 5773 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO ||
5774 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC) {
5774 err = cfg80211_chandef_dfs_required(wdev->wiphy, 5775 err = cfg80211_chandef_dfs_required(wdev->wiphy,
5775 &params.chandef); 5776 &params.chandef);
5776 if (err < 0) { 5777 if (err < 0) {
@@ -6602,6 +6603,9 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
6602 ibss.control_port = 6603 ibss.control_port =
6603 nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]); 6604 nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]);
6604 6605
6606 ibss.userspace_handles_dfs =
6607 nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
6608
6605 err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); 6609 err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
6606 if (err) 6610 if (err)
6607 kfree(connkeys); 6611 kfree(connkeys);
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 3c8be6104ba4..935dea9485da 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1249,7 +1249,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
1249 enum cfg80211_chan_mode chmode; 1249 enum cfg80211_chan_mode chmode;
1250 int num_different_channels = 0; 1250 int num_different_channels = 0;
1251 int total = 1; 1251 int total = 1;
1252 bool radar_required; 1252 bool radar_required = false;
1253 int i, j; 1253 int i, j;
1254 1254
1255 ASSERT_RTNL(); 1255 ASSERT_RTNL();
@@ -1264,14 +1264,20 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
1264 case NL80211_IFTYPE_MESH_POINT: 1264 case NL80211_IFTYPE_MESH_POINT:
1265 case NL80211_IFTYPE_P2P_GO: 1265 case NL80211_IFTYPE_P2P_GO:
1266 case NL80211_IFTYPE_WDS: 1266 case NL80211_IFTYPE_WDS:
1267 radar_required = !!(chan && 1267 /* if the interface could potentially choose a DFS channel,
1268 (chan->flags & IEEE80211_CHAN_RADAR)); 1268 * then mark DFS as required.
1269 */
1270 if (!chan) {
1271 if (chanmode != CHAN_MODE_UNDEFINED && radar_detect)
1272 radar_required = true;
1273 break;
1274 }
1275 radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR);
1269 break; 1276 break;
1270 case NL80211_IFTYPE_P2P_CLIENT: 1277 case NL80211_IFTYPE_P2P_CLIENT:
1271 case NL80211_IFTYPE_STATION: 1278 case NL80211_IFTYPE_STATION:
1272 case NL80211_IFTYPE_P2P_DEVICE: 1279 case NL80211_IFTYPE_P2P_DEVICE:
1273 case NL80211_IFTYPE_MONITOR: 1280 case NL80211_IFTYPE_MONITOR:
1274 radar_required = false;
1275 break; 1281 break;
1276 case NUM_NL80211_IFTYPES: 1282 case NUM_NL80211_IFTYPES:
1277 case NL80211_IFTYPE_UNSPECIFIED: 1283 case NL80211_IFTYPE_UNSPECIFIED: