Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Simon Wunderlich and committed by
Johannes Berg
5336fa88 687da132

+53 -11
+6
include/net/cfg80211.h
··· 1664 1664 * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is 1665 1665 * required to assume that the port is unauthorized until authorized by 1666 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 1670 * @basic_rates: bitmap of basic rates to use when creating the IBSS 1668 1671 * @mcast_rate: per-band multicast rate index + 1 (0: disabled) 1669 1672 * @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask ··· 1684 1681 bool channel_fixed; 1685 1682 bool privacy; 1686 1683 bool control_port; 1684 + bool userspace_handles_dfs; 1687 1685 int mcast_rate[IEEE80211_NUM_BANDS]; 1688 1686 struct ieee80211_ht_cap ht_capa; 1689 1687 struct ieee80211_ht_cap ht_capa_mask; ··· 3065 3061 * @conn: (private) cfg80211 software SME connection state machine data 3066 3062 * @connect_keys: (private) keys to set after connection is established 3067 3063 * @ibss_fixed: (private) IBSS is using fixed BSSID 3064 + * @ibss_dfs_possible: (private) IBSS may change to a DFS channel 3068 3065 * @event_list: (private) list for internal event processing 3069 3066 * @event_lock: (private) lock for event list 3070 3067 */ ··· 3104 3099 struct ieee80211_channel *channel; 3105 3100 3106 3101 bool ibss_fixed; 3102 + bool ibss_dfs_possible; 3107 3103 3108 3104 bool ps; 3109 3105 int ps_timeout;
+9
include/uapi/linux/nl80211.h
··· 1501 1501 * @NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES: array of supported 1502 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 1511 * @NL80211_ATTR_MAX: highest attribute number currently defined 1505 1512 * @__NL80211_ATTR_AFTER_LAST: internal use 1506 1513 */ ··· 1821 1814 NL80211_ATTR_STA_SUPPORTED_CHANNELS, 1822 1815 1823 1816 NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES, 1817 + 1818 + NL80211_ATTR_HANDLE_DFS, 1824 1819 1825 1820 /* add attributes here, update the policy in nl80211.c */ 1826 1821
+2 -1
net/wireless/chan.c
··· 504 504 case NL80211_IFTYPE_ADHOC: 505 505 if (wdev->current_bss) { 506 506 *chan = wdev->current_bss->pub.channel; 507 - *chanmode = wdev->ibss_fixed 507 + *chanmode = (wdev->ibss_fixed && 508 + !wdev->ibss_dfs_possible) 508 509 ? CHAN_MODE_SHARED 509 510 : CHAN_MODE_EXCLUSIVE; 510 511 return;
+20 -4
net/wireless/ibss.c
··· 83 83 struct cfg80211_cached_keys *connkeys) 84 84 { 85 85 struct wireless_dev *wdev = dev->ieee80211_ptr; 86 + struct ieee80211_channel *check_chan; 87 + u8 radar_detect_width = 0; 86 88 int err; 87 89 88 90 ASSERT_WDEV_LOCK(wdev); ··· 116 114 wdev->connect_keys = connkeys; 117 115 118 116 wdev->ibss_fixed = params->channel_fixed; 117 + wdev->ibss_dfs_possible = params->userspace_handles_dfs; 119 118 #ifdef CONFIG_CFG80211_WEXT 120 119 wdev->wext.ibss.chandef = params->chandef; 121 120 #endif 121 + check_chan = params->chandef.chan; 122 + if (params->userspace_handles_dfs) { 123 + /* use channel NULL to check for radar even if the current 124 + * channel is not a radar channel - it might decide to change 125 + * to DFS channel later. 126 + */ 127 + radar_detect_width = BIT(params->chandef.width); 128 + check_chan = NULL; 129 + } 122 130 123 - err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan, 124 - params->channel_fixed 125 - ? CHAN_MODE_SHARED 126 - : CHAN_MODE_EXCLUSIVE); 131 + err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, 132 + check_chan, 133 + (params->channel_fixed && 134 + !radar_detect_width) 135 + ? CHAN_MODE_SHARED 136 + : CHAN_MODE_EXCLUSIVE, 137 + radar_detect_width); 138 + 127 139 if (err) { 128 140 wdev->connect_keys = NULL; 129 141 return err;
+6 -2
net/wireless/nl80211.c
··· 356 356 [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_U16 }, 357 357 [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY }, 358 358 [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY }, 359 + [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG }, 359 360 }; 360 361 361 362 /* policy for the key attributes */ ··· 5769 5768 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef)) 5770 5769 return -EINVAL; 5771 5770 5772 - /* DFS channels are only supported for AP/P2P GO ... for now. */ 5773 5771 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP || 5774 - dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) { 5772 + dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO || 5773 + dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC) { 5775 5774 err = cfg80211_chandef_dfs_required(wdev->wiphy, 5776 5775 &params.chandef); 5777 5776 if (err < 0) { ··· 6602 6601 6603 6602 ibss.control_port = 6604 6603 nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]); 6604 + 6605 + ibss.userspace_handles_dfs = 6606 + nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]); 6605 6607 6606 6608 err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); 6607 6609 if (err)
+10 -4
net/wireless/util.c
··· 1249 1249 enum cfg80211_chan_mode chmode; 1250 1250 int num_different_channels = 0; 1251 1251 int total = 1; 1252 - bool radar_required; 1252 + bool radar_required = false; 1253 1253 int i, j; 1254 1254 1255 1255 ASSERT_RTNL(); ··· 1264 1264 case NL80211_IFTYPE_MESH_POINT: 1265 1265 case NL80211_IFTYPE_P2P_GO: 1266 1266 case NL80211_IFTYPE_WDS: 1267 - radar_required = !!(chan && 1268 - (chan->flags & IEEE80211_CHAN_RADAR)); 1267 + /* if the interface could potentially choose a DFS channel, 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 1276 break; 1270 1277 case NL80211_IFTYPE_P2P_CLIENT: 1271 1278 case NL80211_IFTYPE_STATION: 1272 1279 case NL80211_IFTYPE_P2P_DEVICE: 1273 1280 case NL80211_IFTYPE_MONITOR: 1274 - radar_required = false; 1275 1281 break; 1276 1282 case NUM_NL80211_IFTYPES: 1277 1283 case NL80211_IFTYPE_UNSPECIFIED: