developer | f10a898 | 2022-10-17 12:01:44 +0800 | [diff] [blame] | 1 | From a58aa02645052470e6bacb9e6c1eb7adfb9fc0d8 Mon Sep 17 00:00:00 2001 |
| 2 | From: StanleyYP Wang <StanleyYP.Wang@mediatek.com> |
| 3 | Date: Wed, 5 Oct 2022 19:13:43 +0800 |
| 4 | Subject: [PATCH] mac80211: fix the issue of AP and STA starting on DFS channel |
| 5 | concurrently |
| 6 | |
| 7 | Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com> |
| 8 | --- |
| 9 | include/net/cfg80211.h | 21 ++++++++++++++++ |
| 10 | include/uapi/linux/nl80211.h | 2 +- |
| 11 | net/mac80211/cfg.c | 48 ++++++++++++++++++++++++++++++++++++ |
| 12 | net/mac80211/chan.c | 2 +- |
| 13 | net/wireless/chan.c | 6 ++--- |
| 14 | net/wireless/nl80211.c | 8 ++++++ |
| 15 | net/wireless/rdev-ops.h | 16 ++++++++++++ |
| 16 | net/wireless/trace.h | 15 +++++++++++ |
| 17 | 8 files changed, 113 insertions(+), 5 deletions(-) |
| 18 | |
| 19 | diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h |
| 20 | index f594914..0af069d 100644 |
| 21 | --- a/include/net/cfg80211.h |
| 22 | +++ b/include/net/cfg80211.h |
| 23 | @@ -800,6 +800,24 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1, |
| 24 | chandef1->center_freq2 == chandef2->center_freq2); |
| 25 | } |
| 26 | |
| 27 | +/** |
| 28 | + * cfg80211_chan_fully_overlap - check if two channel are fully overlapped |
| 29 | + * @chandef1: first channel definition |
| 30 | + * @chandef2: second channel definition |
| 31 | + * |
| 32 | + * Return: %true if the channels are valid and fully overlapped, %false otherwise. |
| 33 | + */ |
| 34 | +static inline bool |
| 35 | +cfg80211_chan_fully_overlap(const struct cfg80211_chan_def *chandef1, |
| 36 | + const struct cfg80211_chan_def *chandef2) |
| 37 | +{ |
| 38 | + return (chandef1->center_freq1 != 0 && |
| 39 | + chandef1->center_freq1 == chandef2->center_freq1 && |
| 40 | + chandef1->width == chandef2->width && |
| 41 | + chandef1->freq1_offset == chandef2->freq1_offset && |
| 42 | + chandef1->center_freq2 == chandef2->center_freq2); |
| 43 | +} |
| 44 | + |
| 45 | /** |
| 46 | * cfg80211_chandef_is_edmg - check if chandef represents an EDMG channel |
| 47 | * |
| 48 | @@ -4401,6 +4419,8 @@ struct cfg80211_ops { |
| 49 | struct cfg80211_color_change_settings *params); |
| 50 | int (*set_radar_background)(struct wiphy *wiphy, |
| 51 | struct cfg80211_chan_def *chandef); |
| 52 | + void (*check_cac_skip)(struct wiphy *wiphy, |
| 53 | + struct cfg80211_chan_def *chandef); |
| 54 | }; |
| 55 | |
| 56 | /* |
| 57 | @@ -5554,6 +5574,7 @@ struct wireless_dev { |
| 58 | struct work_struct pmsr_free_wk; |
| 59 | |
| 60 | unsigned long unprot_beacon_reported; |
| 61 | + bool start_disabled; |
| 62 | }; |
| 63 | |
| 64 | static inline u8 *wdev_address(struct wireless_dev *wdev) |
| 65 | diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h |
| 66 | index e674aa7..ada8288 100644 |
| 67 | --- a/include/uapi/linux/nl80211.h |
| 68 | +++ b/include/uapi/linux/nl80211.h |
| 69 | @@ -3129,7 +3129,7 @@ enum nl80211_attrs { |
| 70 | NL80211_ATTR_WIPHY_ANTENNA_GAIN, |
| 71 | |
| 72 | /* add attributes here, update the policy in nl80211.c */ |
| 73 | - |
| 74 | + NL80211_ATTR_START_DISABLED = 999, |
| 75 | __NL80211_ATTR_AFTER_LAST, |
| 76 | NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST, |
| 77 | NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 |
| 78 | diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c |
| 79 | index bf71594..73fb432 100644 |
| 80 | --- a/net/mac80211/cfg.c |
| 81 | +++ b/net/mac80211/cfg.c |
| 82 | @@ -4504,6 +4504,53 @@ ieee80211_set_radar_background(struct wiphy *wiphy, |
| 83 | return local->ops->set_radar_background(&local->hw, chandef); |
| 84 | } |
| 85 | |
| 86 | +static void |
| 87 | +ieee80211_check_cac_skip(struct wiphy *wiphy, |
| 88 | + struct cfg80211_chan_def *chandef) |
| 89 | +{ |
| 90 | + struct ieee80211_local *local = wiphy_priv(wiphy); |
| 91 | + struct ieee80211_sub_if_data *s1; |
| 92 | + struct ieee80211_sub_if_data *s2; |
| 93 | + struct ieee80211_sub_if_data *sdata_sta; |
| 94 | + struct ieee80211_if_managed *ifmgd; |
| 95 | + struct ieee80211_channel *chan; |
| 96 | + struct wireless_dev *wdev; |
| 97 | + unsigned int cac_time_ms; |
| 98 | + |
| 99 | + mutex_lock(&local->mtx); |
| 100 | + /* Bypass AP's cac if there is a STA associated to the same DFS channel */ |
| 101 | + list_for_each_entry(s1, &local->interfaces, list) { |
| 102 | + ifmgd = &s1->u.mgd; |
| 103 | + |
| 104 | + if (s1->vif.type == NL80211_IFTYPE_STATION && ifmgd->associated) |
| 105 | + sdata_sta = s1; |
| 106 | + else |
| 107 | + continue; |
| 108 | + |
| 109 | + list_for_each_entry(s2, &local->interfaces, list) { |
| 110 | + wdev = &s2->wdev; |
| 111 | + chan = wdev->chandef.chan; |
| 112 | + if (chan) { |
| 113 | + if (!(chan->flags & IEEE80211_CHAN_RADAR)) |
| 114 | + continue; |
| 115 | + |
| 116 | + if (wdev->identifier != sdata_sta->wdev.identifier && |
| 117 | + chan->dfs_state == NL80211_DFS_USABLE && wdev->cac_started && |
| 118 | + cfg80211_chan_fully_overlap(&sdata_sta->vif.bss_conf.chandef, |
| 119 | + &s2->vif.bss_conf.chandef)) { |
| 120 | + cac_time_ms = wdev->cac_time_ms; |
| 121 | + wdev->cac_start_time = jiffies - |
| 122 | + msecs_to_jiffies(cac_time_ms + 1); |
| 123 | + cfg80211_cac_event(wdev->netdev, &wdev->chandef, |
| 124 | + NL80211_RADAR_CAC_FINISHED, GFP_KERNEL); |
| 125 | + sdata_info(s2, "Skip CAC on the associated STA's chan\n"); |
| 126 | + } |
| 127 | + } |
| 128 | + } |
| 129 | + } |
| 130 | + mutex_unlock(&local->mtx); |
| 131 | +} |
| 132 | + |
| 133 | const struct cfg80211_ops mac80211_config_ops = { |
| 134 | .add_virtual_intf = ieee80211_add_iface, |
| 135 | .del_virtual_intf = ieee80211_del_iface, |
| 136 | @@ -4610,4 +4657,5 @@ const struct cfg80211_ops mac80211_config_ops = { |
| 137 | .set_sar_specs = ieee80211_set_sar_specs, |
| 138 | .color_change = ieee80211_color_change, |
| 139 | .set_radar_background = ieee80211_set_radar_background, |
| 140 | + .check_cac_skip = ieee80211_check_cac_skip, |
| 141 | }; |
| 142 | diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c |
| 143 | index 63e15f5..5e57e4a 100644 |
| 144 | --- a/net/mac80211/chan.c |
| 145 | +++ b/net/mac80211/chan.c |
| 146 | @@ -505,7 +505,7 @@ bool ieee80211_is_radar_required(struct ieee80211_local *local) |
| 147 | |
| 148 | rcu_read_lock(); |
| 149 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
| 150 | - if (sdata->radar_required) { |
| 151 | + if (sdata->radar_required && sdata->wdev.cac_started) { |
| 152 | rcu_read_unlock(); |
| 153 | return true; |
| 154 | } |
| 155 | diff --git a/net/wireless/chan.c b/net/wireless/chan.c |
| 156 | index 5f50ac4..067ed79 100644 |
| 157 | --- a/net/wireless/chan.c |
| 158 | +++ b/net/wireless/chan.c |
| 159 | @@ -664,13 +664,13 @@ bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev) |
| 160 | switch (wdev->iftype) { |
| 161 | case NL80211_IFTYPE_AP: |
| 162 | case NL80211_IFTYPE_P2P_GO: |
| 163 | - active = wdev->beacon_interval != 0; |
| 164 | + active = wdev->beacon_interval != 0 || wdev->start_disabled; |
| 165 | break; |
| 166 | case NL80211_IFTYPE_ADHOC: |
| 167 | - active = wdev->ssid_len != 0; |
| 168 | + active = wdev->ssid_len != 0 || wdev->start_disabled; |
| 169 | break; |
| 170 | case NL80211_IFTYPE_MESH_POINT: |
| 171 | - active = wdev->mesh_id_len != 0; |
| 172 | + active = wdev->mesh_id_len != 0 || wdev->start_disabled; |
| 173 | break; |
| 174 | case NL80211_IFTYPE_STATION: |
| 175 | case NL80211_IFTYPE_OCB: |
| 176 | diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c |
| 177 | index a20aba5..8dc928d 100644 |
| 178 | --- a/net/wireless/nl80211.c |
| 179 | +++ b/net/wireless/nl80211.c |
| 180 | @@ -803,6 +803,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { |
| 181 | NLA_POLICY_NESTED(nl80211_mbssid_config_policy), |
| 182 | [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED }, |
| 183 | [NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG }, |
| 184 | + [NL80211_ATTR_START_DISABLED] = { .type = NLA_FLAG }, |
| 185 | [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 }, |
| 186 | }; |
| 187 | |
| 188 | @@ -5547,6 +5548,12 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) |
| 189 | |
| 190 | memset(¶ms, 0, sizeof(params)); |
| 191 | |
| 192 | + if (info->attrs[NL80211_ATTR_START_DISABLED]) { |
| 193 | + wdev->start_disabled = nla_get_flag(info->attrs[NL80211_ATTR_START_DISABLED]); |
| 194 | + err = 0; |
| 195 | + goto out; |
| 196 | + } |
| 197 | + |
| 198 | /* these are required for START_AP */ |
| 199 | if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || |
| 200 | !info->attrs[NL80211_ATTR_DTIM_PERIOD] || |
| 201 | @@ -9393,6 +9400,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, |
| 202 | wdev->cac_started = true; |
| 203 | wdev->cac_start_time = jiffies; |
| 204 | wdev->cac_time_ms = cac_time_ms; |
| 205 | + err = rdev_check_cac_skip(rdev, &wdev->chandef); |
| 206 | } |
| 207 | unlock: |
| 208 | wiphy_unlock(wiphy); |
| 209 | diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h |
| 210 | index 8555468..e7d0064 100644 |
| 211 | --- a/net/wireless/rdev-ops.h |
| 212 | +++ b/net/wireless/rdev-ops.h |
| 213 | @@ -1398,4 +1398,20 @@ rdev_set_radar_background(struct cfg80211_registered_device *rdev, |
| 214 | return ret; |
| 215 | } |
| 216 | |
| 217 | +static inline int |
| 218 | +rdev_check_cac_skip(struct cfg80211_registered_device *rdev, |
| 219 | + struct cfg80211_chan_def *chandef) |
| 220 | +{ |
| 221 | + struct wiphy *wiphy = &rdev->wiphy; |
| 222 | + |
| 223 | + if (!rdev->ops->check_cac_skip) |
| 224 | + return -EOPNOTSUPP; |
| 225 | + |
| 226 | + trace_rdev_check_cac_skip(wiphy, chandef); |
| 227 | + rdev->ops->check_cac_skip(wiphy, chandef); |
| 228 | + trace_rdev_return_void(wiphy); |
| 229 | + |
| 230 | + return 0; |
| 231 | +} |
| 232 | + |
| 233 | #endif /* __CFG80211_RDEV_OPS */ |
| 234 | diff --git a/net/wireless/trace.h b/net/wireless/trace.h |
| 235 | index 97a2937..e3f1c79 100644 |
| 236 | --- a/net/wireless/trace.h |
| 237 | +++ b/net/wireless/trace.h |
| 238 | @@ -3665,6 +3665,21 @@ TRACE_EVENT(rdev_set_radar_background, |
| 239 | WIPHY_PR_ARG, CHAN_DEF_PR_ARG) |
| 240 | ); |
| 241 | |
| 242 | +TRACE_EVENT(rdev_check_cac_skip, |
| 243 | + TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), |
| 244 | + |
| 245 | + TP_ARGS(wiphy, chandef), |
| 246 | + |
| 247 | + TP_STRUCT__entry(WIPHY_ENTRY |
| 248 | + CHAN_DEF_ENTRY), |
| 249 | + |
| 250 | + TP_fast_assign(WIPHY_ASSIGN; |
| 251 | + CHAN_DEF_ASSIGN(chandef)), |
| 252 | + |
| 253 | + TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, |
| 254 | + WIPHY_PR_ARG, CHAN_DEF_PR_ARG) |
| 255 | +); |
| 256 | + |
| 257 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ |
| 258 | |
| 259 | #undef TRACE_INCLUDE_PATH |
| 260 | -- |
| 261 | 2.18.0 |
| 262 | |