developer | 36fe709 | 2023-09-27 12:24:47 +0800 | [diff] [blame^] | 1 | From bd54f3c29077f23dad92ef82a78061b40be30c65 Mon Sep 17 00:00:00 2001 |
| 2 | From: Aloka Dixit <quic_alokad@quicinc.com> |
| 3 | Date: Mon, 5 Dec 2022 16:50:37 -0800 |
| 4 | Subject: [PATCH] wifi: mac80211: generate EMA beacons in AP mode |
| 5 | |
| 6 | Add APIs to generate an array of beacons for an EMA AP (enhanced |
| 7 | multiple BSSID advertisements), each including a single MBSSID element. |
| 8 | EMA profile periodicity equals the count of elements. |
| 9 | |
| 10 | - ieee80211_beacon_get_template_ema_list() - Generate and return all |
| 11 | EMA beacon templates. Drivers must call ieee80211_beacon_free_ema_list() |
| 12 | to free the memory. No change in the prototype for the existing API, |
| 13 | ieee80211_beacon_get_template(), which should be used for non-EMA AP. |
| 14 | |
| 15 | - ieee80211_beacon_get_template_ema_index() - Generate a beacon which |
| 16 | includes the multiple BSSID element at the given index. Drivers can use |
| 17 | this function in a loop until NULL is returned which indicates end of |
| 18 | available MBSSID elements. |
| 19 | |
| 20 | - ieee80211_beacon_free_ema_list() - free the memory allocated for the |
| 21 | list of EMA beacon templates. |
| 22 | |
| 23 | Modify existing functions ieee80211_beacon_get_ap(), |
| 24 | ieee80211_get_mbssid_beacon_len() and ieee80211_beacon_add_mbssid() |
| 25 | to accept a new parameter for EMA index. |
| 26 | |
| 27 | Signed-off-by: Aloka Dixit <quic_alokad@quicinc.com> |
| 28 | Co-developed-by: John Crispin <john@phrozen.org> |
| 29 | Signed-off-by: John Crispin <john@phrozen.org> |
| 30 | Link: https://lore.kernel.org/r/20221206005040.3177-2-quic_alokad@quicinc.com |
| 31 | Signed-off-by: Johannes Berg <johannes.berg@intel.com> |
| 32 | --- |
| 33 | include/net/mac80211.h | 68 +++++++++++++++++++ |
| 34 | net/mac80211/cfg.c | 11 +-- |
| 35 | net/mac80211/ieee80211_i.h | 10 ++- |
| 36 | net/mac80211/tx.c | 134 ++++++++++++++++++++++++++++++++++--- |
| 37 | 4 files changed, 205 insertions(+), 18 deletions(-) |
| 38 | |
| 39 | --- a/include/net/mac80211.h |
| 40 | +++ b/include/net/mac80211.h |
| 41 | @@ -5252,6 +5252,74 @@ ieee80211_beacon_get_template(struct iee |
| 42 | unsigned int link_id); |
| 43 | |
| 44 | /** |
| 45 | + * ieee80211_beacon_get_template_ema_index - EMA beacon template generation |
| 46 | + * @hw: pointer obtained from ieee80211_alloc_hw(). |
| 47 | + * @vif: &struct ieee80211_vif pointer from the add_interface callback. |
| 48 | + * @offs: &struct ieee80211_mutable_offsets pointer to struct that will |
| 49 | + * receive the offsets that may be updated by the driver. |
| 50 | + * @link_id: the link id to which the beacon belongs (or 0 for a non-MLD AP). |
| 51 | + * @ema_index: index of the beacon in the EMA set. |
| 52 | + * |
| 53 | + * This function follows the same rules as ieee80211_beacon_get_template() |
| 54 | + * but returns a beacon template which includes multiple BSSID element at the |
| 55 | + * requested index. |
| 56 | + * |
| 57 | + * Return: The beacon template. %NULL indicates the end of EMA templates. |
| 58 | + */ |
| 59 | +struct sk_buff * |
| 60 | +ieee80211_beacon_get_template_ema_index(struct ieee80211_hw *hw, |
| 61 | + struct ieee80211_vif *vif, |
| 62 | + struct ieee80211_mutable_offsets *offs, |
| 63 | + unsigned int link_id, u8 ema_index); |
| 64 | + |
| 65 | +/** |
| 66 | + * struct ieee80211_ema_beacons - List of EMA beacons |
| 67 | + * @cnt: count of EMA beacons. |
| 68 | + * |
| 69 | + * @bcn: array of EMA beacons. |
| 70 | + * @bcn.skb: the skb containing this specific beacon |
| 71 | + * @bcn.offs: &struct ieee80211_mutable_offsets pointer to struct that will |
| 72 | + * receive the offsets that may be updated by the driver. |
| 73 | + */ |
| 74 | +struct ieee80211_ema_beacons { |
| 75 | + u8 cnt; |
| 76 | + struct { |
| 77 | + struct sk_buff *skb; |
| 78 | + struct ieee80211_mutable_offsets offs; |
| 79 | + } bcn[]; |
| 80 | +}; |
| 81 | + |
| 82 | +/** |
| 83 | + * ieee80211_beacon_get_template_ema_list - EMA beacon template generation |
| 84 | + * @hw: pointer obtained from ieee80211_alloc_hw(). |
| 85 | + * @vif: &struct ieee80211_vif pointer from the add_interface callback. |
| 86 | + * @link_id: the link id to which the beacon belongs (or 0 for a non-MLD AP) |
| 87 | + * |
| 88 | + * This function follows the same rules as ieee80211_beacon_get_template() |
| 89 | + * but allocates and returns a pointer to list of all beacon templates required |
| 90 | + * to cover all profiles in the multiple BSSID set. Each template includes only |
| 91 | + * one multiple BSSID element. |
| 92 | + * |
| 93 | + * Driver must call ieee80211_beacon_free_ema_list() to free the memory. |
| 94 | + * |
| 95 | + * Return: EMA beacon templates of type struct ieee80211_ema_beacons *. |
| 96 | + * %NULL on error. |
| 97 | + */ |
| 98 | +struct ieee80211_ema_beacons * |
| 99 | +ieee80211_beacon_get_template_ema_list(struct ieee80211_hw *hw, |
| 100 | + struct ieee80211_vif *vif, |
| 101 | + unsigned int link_id); |
| 102 | + |
| 103 | +/** |
| 104 | + * ieee80211_beacon_free_ema_list - free an EMA beacon template list |
| 105 | + * @ema_beacons: list of EMA beacons of type &struct ieee80211_ema_beacons pointers. |
| 106 | + * |
| 107 | + * This function will free a list previously acquired by calling |
| 108 | + * ieee80211_beacon_get_template_ema_list() |
| 109 | + */ |
| 110 | +void ieee80211_beacon_free_ema_list(struct ieee80211_ema_beacons *ema_beacons); |
| 111 | + |
| 112 | +/** |
| 113 | * ieee80211_beacon_get_tim - beacon generation function |
| 114 | * @hw: pointer obtained from ieee80211_alloc_hw(). |
| 115 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. |
| 116 | --- a/net/mac80211/cfg.c |
| 117 | +++ b/net/mac80211/cfg.c |
| 118 | @@ -1122,11 +1122,11 @@ static int ieee80211_assign_beacon(struc |
| 119 | if (params->mbssid_ies) { |
| 120 | mbssid = params->mbssid_ies; |
| 121 | size += struct_size(new->mbssid_ies, elem, mbssid->cnt); |
| 122 | - size += ieee80211_get_mbssid_beacon_len(mbssid); |
| 123 | + size += ieee80211_get_mbssid_beacon_len(mbssid, mbssid->cnt); |
| 124 | } else if (old && old->mbssid_ies) { |
| 125 | mbssid = old->mbssid_ies; |
| 126 | size += struct_size(new->mbssid_ies, elem, mbssid->cnt); |
| 127 | - size += ieee80211_get_mbssid_beacon_len(mbssid); |
| 128 | + size += ieee80211_get_mbssid_beacon_len(mbssid, mbssid->cnt); |
| 129 | } |
| 130 | |
| 131 | new = kzalloc(size, GFP_KERNEL); |
| 132 | @@ -3384,8 +3384,11 @@ cfg80211_beacon_dup(struct cfg80211_beac |
| 133 | |
| 134 | len = beacon->head_len + beacon->tail_len + beacon->beacon_ies_len + |
| 135 | beacon->proberesp_ies_len + beacon->assocresp_ies_len + |
| 136 | - beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len + |
| 137 | - ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies); |
| 138 | + beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len; |
| 139 | + |
| 140 | + if (beacon->mbssid_ies) |
| 141 | + len += ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies, |
| 142 | + beacon->mbssid_ies->cnt); |
| 143 | |
| 144 | new_beacon = kzalloc(sizeof(*new_beacon) + len, GFP_KERNEL); |
| 145 | if (!new_beacon) |
| 146 | --- a/net/mac80211/ieee80211_i.h |
| 147 | +++ b/net/mac80211/ieee80211_i.h |
| 148 | @@ -1182,13 +1182,17 @@ ieee80211_vif_get_shift(struct ieee80211 |
| 149 | } |
| 150 | |
| 151 | static inline int |
| 152 | -ieee80211_get_mbssid_beacon_len(struct cfg80211_mbssid_elems *elems) |
| 153 | +ieee80211_get_mbssid_beacon_len(struct cfg80211_mbssid_elems *elems, u8 i) |
| 154 | { |
| 155 | - int i, len = 0; |
| 156 | + int len = 0; |
| 157 | |
| 158 | - if (!elems) |
| 159 | + if (!elems || !elems->cnt || i > elems->cnt) |
| 160 | return 0; |
| 161 | |
| 162 | + if (i < elems->cnt) |
| 163 | + return elems->elem[i].len; |
| 164 | + |
| 165 | + /* i == elems->cnt, calculate total length of all MBSSID elements */ |
| 166 | for (i = 0; i < elems->cnt; i++) |
| 167 | len += elems->elem[i].len; |
| 168 | |
| 169 | --- a/net/mac80211/tx.c |
| 170 | +++ b/net/mac80211/tx.c |
| 171 | @@ -5205,13 +5205,20 @@ ieee80211_beacon_get_finish(struct ieee8 |
| 172 | } |
| 173 | |
| 174 | static void |
| 175 | -ieee80211_beacon_add_mbssid(struct sk_buff *skb, struct beacon_data *beacon) |
| 176 | +ieee80211_beacon_add_mbssid(struct sk_buff *skb, struct beacon_data *beacon, |
| 177 | + u8 i) |
| 178 | { |
| 179 | - int i; |
| 180 | + if (!beacon->mbssid_ies || !beacon->mbssid_ies->cnt || |
| 181 | + i > beacon->mbssid_ies->cnt) |
| 182 | + return; |
| 183 | |
| 184 | - if (!beacon->mbssid_ies) |
| 185 | + if (i < beacon->mbssid_ies->cnt) { |
| 186 | + skb_put_data(skb, beacon->mbssid_ies->elem[i].data, |
| 187 | + beacon->mbssid_ies->elem[i].len); |
| 188 | return; |
| 189 | + } |
| 190 | |
| 191 | + /* i == beacon->mbssid_ies->cnt, include all MBSSID elements */ |
| 192 | for (i = 0; i < beacon->mbssid_ies->cnt; i++) |
| 193 | skb_put_data(skb, beacon->mbssid_ies->elem[i].data, |
| 194 | beacon->mbssid_ies->elem[i].len); |
| 195 | @@ -5224,7 +5231,8 @@ ieee80211_beacon_get_ap(struct ieee80211 |
| 196 | struct ieee80211_mutable_offsets *offs, |
| 197 | bool is_template, |
| 198 | struct beacon_data *beacon, |
| 199 | - struct ieee80211_chanctx_conf *chanctx_conf) |
| 200 | + struct ieee80211_chanctx_conf *chanctx_conf, |
| 201 | + u8 ema_index) |
| 202 | { |
| 203 | struct ieee80211_local *local = hw_to_local(hw); |
| 204 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
| 205 | @@ -5243,7 +5251,9 @@ ieee80211_beacon_get_ap(struct ieee80211 |
| 206 | /* headroom, head length, |
| 207 | * tail length, maximum TIM length and multiple BSSID length |
| 208 | */ |
| 209 | - mbssid_len = ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies); |
| 210 | + mbssid_len = ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies, |
| 211 | + ema_index); |
| 212 | + |
| 213 | skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + |
| 214 | beacon->tail_len + 256 + |
| 215 | local->hw.extra_beacon_tailroom + mbssid_len); |
| 216 | @@ -5261,7 +5271,7 @@ ieee80211_beacon_get_ap(struct ieee80211 |
| 217 | offs->cntdwn_counter_offs[0] = beacon->cntdwn_counter_offsets[0]; |
| 218 | |
| 219 | if (mbssid_len) { |
| 220 | - ieee80211_beacon_add_mbssid(skb, beacon); |
| 221 | + ieee80211_beacon_add_mbssid(skb, beacon, ema_index); |
| 222 | offs->mbssid_off = skb->len - mbssid_len; |
| 223 | } |
| 224 | |
| 225 | @@ -5280,12 +5290,51 @@ ieee80211_beacon_get_ap(struct ieee80211 |
| 226 | return skb; |
| 227 | } |
| 228 | |
| 229 | +static struct ieee80211_ema_beacons * |
| 230 | +ieee80211_beacon_get_ap_ema_list(struct ieee80211_hw *hw, |
| 231 | + struct ieee80211_vif *vif, |
| 232 | + struct ieee80211_link_data *link, |
| 233 | + struct ieee80211_mutable_offsets *offs, |
| 234 | + bool is_template, struct beacon_data *beacon, |
| 235 | + struct ieee80211_chanctx_conf *chanctx_conf) |
| 236 | +{ |
| 237 | + struct ieee80211_ema_beacons *ema = NULL; |
| 238 | + |
| 239 | + if (!beacon->mbssid_ies || !beacon->mbssid_ies->cnt) |
| 240 | + return NULL; |
| 241 | + |
| 242 | + ema = kzalloc(struct_size(ema, bcn, beacon->mbssid_ies->cnt), |
| 243 | + GFP_ATOMIC); |
| 244 | + if (!ema) |
| 245 | + return NULL; |
| 246 | + |
| 247 | + for (ema->cnt = 0; ema->cnt < beacon->mbssid_ies->cnt; ema->cnt++) { |
| 248 | + ema->bcn[ema->cnt].skb = |
| 249 | + ieee80211_beacon_get_ap(hw, vif, link, |
| 250 | + &ema->bcn[ema->cnt].offs, |
| 251 | + is_template, beacon, |
| 252 | + chanctx_conf, ema->cnt); |
| 253 | + if (!ema->bcn[ema->cnt].skb) |
| 254 | + break; |
| 255 | + } |
| 256 | + |
| 257 | + if (ema->cnt == beacon->mbssid_ies->cnt) |
| 258 | + return ema; |
| 259 | + |
| 260 | + ieee80211_beacon_free_ema_list(ema); |
| 261 | + return NULL; |
| 262 | +} |
| 263 | + |
| 264 | +#define IEEE80211_INCLUDE_ALL_MBSSID_ELEMS -1 |
| 265 | + |
| 266 | static struct sk_buff * |
| 267 | __ieee80211_beacon_get(struct ieee80211_hw *hw, |
| 268 | struct ieee80211_vif *vif, |
| 269 | struct ieee80211_mutable_offsets *offs, |
| 270 | bool is_template, |
| 271 | - unsigned int link_id) |
| 272 | + unsigned int link_id, |
| 273 | + int ema_index, |
| 274 | + struct ieee80211_ema_beacons **ema_beacons) |
| 275 | { |
| 276 | struct ieee80211_local *local = hw_to_local(hw); |
| 277 | struct beacon_data *beacon = NULL; |
| 278 | @@ -5314,8 +5363,29 @@ __ieee80211_beacon_get(struct ieee80211_ |
| 279 | if (!beacon) |
| 280 | goto out; |
| 281 | |
| 282 | - skb = ieee80211_beacon_get_ap(hw, vif, link, offs, is_template, |
| 283 | - beacon, chanctx_conf); |
| 284 | + if (ema_beacons) { |
| 285 | + *ema_beacons = |
| 286 | + ieee80211_beacon_get_ap_ema_list(hw, vif, link, |
| 287 | + offs, |
| 288 | + is_template, |
| 289 | + beacon, |
| 290 | + chanctx_conf); |
| 291 | + } else { |
| 292 | + if (beacon->mbssid_ies && beacon->mbssid_ies->cnt) { |
| 293 | + if (ema_index >= beacon->mbssid_ies->cnt) |
| 294 | + goto out; /* End of MBSSID elements */ |
| 295 | + |
| 296 | + if (ema_index <= IEEE80211_INCLUDE_ALL_MBSSID_ELEMS) |
| 297 | + ema_index = beacon->mbssid_ies->cnt; |
| 298 | + } else { |
| 299 | + ema_index = 0; |
| 300 | + } |
| 301 | + |
| 302 | + skb = ieee80211_beacon_get_ap(hw, vif, link, offs, |
| 303 | + is_template, beacon, |
| 304 | + chanctx_conf, |
| 305 | + ema_index); |
| 306 | + } |
| 307 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
| 308 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
| 309 | struct ieee80211_hdr *hdr; |
| 310 | @@ -5403,10 +5473,50 @@ ieee80211_beacon_get_template(struct iee |
| 311 | struct ieee80211_mutable_offsets *offs, |
| 312 | unsigned int link_id) |
| 313 | { |
| 314 | - return __ieee80211_beacon_get(hw, vif, offs, true, link_id); |
| 315 | + return __ieee80211_beacon_get(hw, vif, offs, true, link_id, |
| 316 | + IEEE80211_INCLUDE_ALL_MBSSID_ELEMS, NULL); |
| 317 | } |
| 318 | EXPORT_SYMBOL(ieee80211_beacon_get_template); |
| 319 | |
| 320 | +struct sk_buff * |
| 321 | +ieee80211_beacon_get_template_ema_index(struct ieee80211_hw *hw, |
| 322 | + struct ieee80211_vif *vif, |
| 323 | + struct ieee80211_mutable_offsets *offs, |
| 324 | + unsigned int link_id, u8 ema_index) |
| 325 | +{ |
| 326 | + return __ieee80211_beacon_get(hw, vif, offs, true, link_id, ema_index, |
| 327 | + NULL); |
| 328 | +} |
| 329 | +EXPORT_SYMBOL(ieee80211_beacon_get_template_ema_index); |
| 330 | + |
| 331 | +void ieee80211_beacon_free_ema_list(struct ieee80211_ema_beacons *ema_beacons) |
| 332 | +{ |
| 333 | + u8 i; |
| 334 | + |
| 335 | + if (!ema_beacons) |
| 336 | + return; |
| 337 | + |
| 338 | + for (i = 0; i < ema_beacons->cnt; i++) |
| 339 | + kfree_skb(ema_beacons->bcn[i].skb); |
| 340 | + |
| 341 | + kfree(ema_beacons); |
| 342 | +} |
| 343 | +EXPORT_SYMBOL(ieee80211_beacon_free_ema_list); |
| 344 | + |
| 345 | +struct ieee80211_ema_beacons * |
| 346 | +ieee80211_beacon_get_template_ema_list(struct ieee80211_hw *hw, |
| 347 | + struct ieee80211_vif *vif, |
| 348 | + unsigned int link_id) |
| 349 | +{ |
| 350 | + struct ieee80211_ema_beacons *ema_beacons = NULL; |
| 351 | + |
| 352 | + WARN_ON(__ieee80211_beacon_get(hw, vif, NULL, false, link_id, 0, |
| 353 | + &ema_beacons)); |
| 354 | + |
| 355 | + return ema_beacons; |
| 356 | +} |
| 357 | +EXPORT_SYMBOL(ieee80211_beacon_get_template_ema_list); |
| 358 | + |
| 359 | struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, |
| 360 | struct ieee80211_vif *vif, |
| 361 | u16 *tim_offset, u16 *tim_length, |
| 362 | @@ -5414,7 +5524,9 @@ struct sk_buff *ieee80211_beacon_get_tim |
| 363 | { |
| 364 | struct ieee80211_mutable_offsets offs = {}; |
| 365 | struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false, |
| 366 | - link_id); |
| 367 | + link_id, |
| 368 | + IEEE80211_INCLUDE_ALL_MBSSID_ELEMS, |
| 369 | + NULL); |
| 370 | struct sk_buff *copy; |
| 371 | int shift; |
| 372 | |