1 From fb4fc65312a19630f7726e2bd992931349daebee Mon Sep 17 00:00:00 2001
2 From: John Crispin <john@phrozen.org>
3 Date: Tue, 6 Oct 2020 15:51:59 +0200
4 Subject: [PATCH 3/4] mac80211: add multiple bssid/EMA support to beacon
7 With beacon_data now holding the additional information about the multiple
8 bssid elements, we need to honour these in the various beacon handling
11 Extend ieee80211_beacon_get_template() to allow generation of EMA beacons.
12 The API provides support for HW that can offload the EMA beaconing aswell
13 as HW that will require periodic updates of the beacon template.
15 Signed-off-by: John Crispin <john@phrozen.org>
17 include/net/mac80211.h | 92 +++++++++++++++++++++-
18 net/mac80211/cfg.c | 59 +++++++++++++-
19 net/mac80211/ieee80211_i.h | 2 +
20 net/mac80211/tx.c | 156 +++++++++++++++++++++++++++++++++----
21 4 files changed, 288 insertions(+), 21 deletions(-)
23 Index: backports-5.8-1/include/net/mac80211.h
24 ===================================================================
25 --- backports-5.8-1.orig/include/net/mac80211.h
26 +++ backports-5.8-1/include/net/mac80211.h
27 @@ -4834,6 +4834,8 @@ struct ieee80211_mutable_offsets {
30 u16 csa_counter_offs[IEEE80211_MAX_CSA_COUNTERS_NUM];
31 + u16 multiple_bssid_offset;
32 + u16 multiple_bssid_length;
36 @@ -4861,6 +4863,91 @@ ieee80211_beacon_get_template(struct iee
37 struct ieee80211_mutable_offsets *offs);
40 + * enum ieee80211_bcn_tmpl_ema - EMA beacon generation type
41 + * @IEEE80211_BCN_EMA_NONE: don't generate an EMA beacon.
42 + * @IEEE80211_BCN_EMA_NEXT: generate the next periodicity beacon.
43 + * @IEEE80211_BCN_EMA_INDEX: generate beacon by periodicity index
44 + * if the value is >= this enum value.
46 +enum ieee80211_bcn_tmpl_ema {
47 + IEEE80211_BCN_EMA_NONE = -2,
48 + IEEE80211_BCN_EMA_NEXT = -1,
49 + IEEE80211_BCN_EMA_INDEX = 0,
53 + * ieee80211_beacon_get_template_ema_next - EMA beacon template generation
54 + * function for drivers using the sw offload path.
55 + * @hw: pointer obtained from ieee80211_alloc_hw().
56 + * @vif: &struct ieee80211_vif pointer from the add_interface callback.
57 + * @offs: &struct ieee80211_mutable_offsets pointer to struct that will
58 + * receive the offsets that may be updated by the driver.
60 + * This function differs from ieee80211_beacon_get_template in the sense that
61 + * it generates EMA VAP templates. When we use multiple_bssid, the beacons can
62 + * get very large costing a lot of airtime. To work around this, we iterate
63 + * over the multiple bssid elements and only send one inside the beacon for
64 + * 1..n. Calling this function will auto-increment the periodicity counter.
66 + * This function needs to follow the same rules as ieee80211_beacon_get_template
68 + * Return: The beacon template. %NULL on error.
72 +ieee80211_beacon_get_template_ema_next(struct ieee80211_hw *hw,
73 + struct ieee80211_vif *vif,
74 + struct ieee80211_mutable_offsets *offs);
76 +/** struct ieee80211_ema_bcn_list - list entry of an EMA beacon
77 + * @list: the list pointer.
78 + * @skb: the skb containing this specific beacon
79 + * @offs: &struct ieee80211_mutable_offsets pointer to struct that will
80 + * receive the offsets that may be updated by the driver.
82 +struct ieee80211_ema_bcn_list {
83 + struct list_head list;
84 + struct sk_buff * skb;
85 + struct ieee80211_mutable_offsets offs;
89 + * ieee80211_beacon_get_template_ema_list - EMA beacon template generation
90 + * function for drivers using the hw offload.
91 + * @hw: pointer obtained from ieee80211_alloc_hw().
92 + * @vif: &struct ieee80211_vif pointer from the add_interface callback.
93 + * @head: linked list head that will get populated with
94 + * &struct ieee80211_ema_bcn_list pointers.
96 + * This function differs from ieee80211_beacon_get_template in the sense that
97 + * it generates EMA VAP templates. When we use multiple_bssid, the beacons can
98 + * get very large costing a lot of airtime. To work around this, we iterate
99 + * over the multiple bssid elements and only send one inside the beacon for
100 + * 1..n. This function will populate a linked list that the driver can pass
103 + * This function needs to follow the same rules as ieee80211_beacon_get_template
105 + * Return: The nuber of entries in the list or 0 on error.
109 +ieee80211_beacon_get_template_ema_list(struct ieee80211_hw *hw,
110 + struct ieee80211_vif *vif,
111 + struct list_head *head);
114 + * ieee80211_beacon_free_ema_list - free an EMA beacon template list
115 + * @head: linked list head containing &struct ieee80211_ema_bcn_list pointers.
117 + * This function will free a list previously acquired by calling
118 + * ieee80211_beacon_get_template_ema_list()
122 +ieee80211_beacon_free_ema_list(struct list_head *head);
125 * ieee80211_beacon_get_tim - beacon generation function
126 * @hw: pointer obtained from ieee80211_alloc_hw().
127 * @vif: &struct ieee80211_vif pointer from the add_interface callback.
128 Index: backports-5.8-1/net/mac80211/cfg.c
129 ===================================================================
130 --- backports-5.8-1.orig/net/mac80211/cfg.c
131 +++ backports-5.8-1/net/mac80211/cfg.c
132 @@ -929,12 +929,38 @@ static int ieee80211_set_ftm_responder_p
136 +static int ieee80211_get_multiple_bssid_beacon_len(struct cfg80211_multiple_bssid_data *data)
140 + for (i = 0; i < data->cnt; i++)
141 + len += data->len[i];
146 +static u8 *ieee80211_copy_multiple_bssid_beacon(u8 *offset,
147 + struct cfg80211_multiple_bssid_data *new,
148 + struct cfg80211_multiple_bssid_data *old)
153 + for (i = 0; i < new->cnt; i++) {
154 + new->ies[i] = offset;
155 + memcpy(new->ies[i], old->ies[i], new->len[i]);
156 + offset += new->len[i];
161 static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
162 struct cfg80211_beacon_data *params,
163 const struct ieee80211_csa_settings *csa)
165 struct beacon_data *new, *old;
166 - int new_head_len, new_tail_len;
167 + int new_head_len, new_tail_len, new_multiple_bssid_len;
168 + u8 *new_multiple_bssid_offset;
170 u32 changed = BSS_CHANGED_BEACON;
172 @@ -958,7 +984,15 @@ static int ieee80211_assign_beacon(struc
174 new_tail_len = old->tail_len;
176 - size = sizeof(*new) + new_head_len + new_tail_len;
177 + /* new or old multiple_bssid? */
178 + if (params->multiple_bssid.cnt || !old)
179 + new_multiple_bssid_len =
180 + ieee80211_get_multiple_bssid_beacon_len(¶ms->multiple_bssid);
182 + new_multiple_bssid_len =
183 + ieee80211_get_multiple_bssid_beacon_len(&old->multiple_bssid);
185 + size = sizeof(*new) + new_head_len + new_tail_len + new_multiple_bssid_len;
187 new = kzalloc(size, GFP_KERNEL);
189 @@ -975,6 +1009,18 @@ static int ieee80211_assign_beacon(struc
190 new->head_len = new_head_len;
191 new->tail_len = new_tail_len;
193 + new_multiple_bssid_offset = new->tail + new_tail_len;
195 + /* copy in optional multiple_bssid_ies */
196 + if (params->multiple_bssid.cnt)
197 + ieee80211_copy_multiple_bssid_beacon(new_multiple_bssid_offset,
198 + &new->multiple_bssid,
199 + ¶ms->multiple_bssid);
200 + else if (old && old->multiple_bssid.cnt)
201 + ieee80211_copy_multiple_bssid_beacon(new_multiple_bssid_offset,
202 + &new->multiple_bssid,
203 + &old->multiple_bssid);
206 new->csa_current_counter = csa->count;
207 memcpy(new->csa_counter_offsets, csa->counter_offsets_beacon,
208 @@ -3011,7 +3057,8 @@ cfg80211_beacon_dup(struct cfg80211_beac
210 len = beacon->head_len + beacon->tail_len + beacon->beacon_ies_len +
211 beacon->proberesp_ies_len + beacon->assocresp_ies_len +
212 - beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len;
213 + beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len +
214 + ieee80211_get_multiple_bssid_beacon_len(&beacon->multiple_bssid);
216 new_beacon = kzalloc(sizeof(*new_beacon) + len, GFP_KERNEL);
218 @@ -3054,6 +3101,10 @@ cfg80211_beacon_dup(struct cfg80211_beac
219 memcpy(pos, beacon->probe_resp, beacon->probe_resp_len);
220 pos += beacon->probe_resp_len;
222 + if (beacon->multiple_bssid.cnt)
223 + pos = ieee80211_copy_multiple_bssid_beacon(pos,
224 + &new_beacon->multiple_bssid,
225 + &beacon->multiple_bssid);
227 /* might copy -1, meaning no changes requested */
228 new_beacon->ftm_responder = beacon->ftm_responder;
229 Index: backports-5.8-1/net/mac80211/ieee80211_i.h
230 ===================================================================
231 --- backports-5.8-1.orig/net/mac80211/ieee80211_i.h
232 +++ backports-5.8-1/net/mac80211/ieee80211_i.h
233 @@ -262,6 +262,8 @@ struct beacon_data {
234 struct ieee80211_meshconf_ie *meshconf;
235 u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM];
236 u8 csa_current_counter;
237 + struct cfg80211_multiple_bssid_data multiple_bssid;
239 struct rcu_head rcu_head;
242 Index: backports-5.8-1/net/mac80211/tx.c
243 ===================================================================
244 --- backports-5.8-1.orig/net/mac80211/tx.c
245 +++ backports-5.8-1/net/mac80211/tx.c
246 @@ -4719,11 +4719,26 @@ static int ieee80211_beacon_protect(stru
251 +ieee80211_beacon_add_multiple_bssid_config(struct ieee80211_vif *vif, struct sk_buff *skb,
252 + struct cfg80211_multiple_bssid_data *config)
254 + u8 *pos = skb_put(skb, 6);
256 + *pos++ = WLAN_EID_EXTENSION;
258 + *pos++ = WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION;
260 + *pos++ = vif->bss_conf.multiple_bssid.count;
261 + *pos++ = config->cnt;
264 static struct sk_buff *
265 __ieee80211_beacon_get(struct ieee80211_hw *hw,
266 struct ieee80211_vif *vif,
267 struct ieee80211_mutable_offsets *offs,
272 struct ieee80211_local *local = hw_to_local(hw);
273 struct beacon_data *beacon = NULL;
274 @@ -4735,13 +4750,11 @@ __ieee80211_beacon_get(struct ieee80211_
275 struct ieee80211_chanctx_conf *chanctx_conf;
276 int csa_off_base = 0;
280 sdata = vif_to_sdata(vif);
281 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
283 if (!ieee80211_sdata_running(sdata) || !chanctx_conf)
288 memset(offs, 0, sizeof(*offs));
289 @@ -4751,6 +4764,8 @@ __ieee80211_beacon_get(struct ieee80211_
291 beacon = rcu_dereference(ap->beacon);
293 + int multiple_bssid_len = 0;
295 if (beacon->csa_counter_offsets[0]) {
297 __ieee80211_csa_update_counter(beacon);
298 @@ -4758,6 +4773,27 @@ __ieee80211_beacon_get(struct ieee80211_
299 ieee80211_set_csa(sdata, beacon);
302 + if (ema_index == IEEE80211_BCN_EMA_NEXT) {
303 + ema_index = beacon->ema_index;
304 + beacon->ema_index++;
305 + beacon->ema_index %= beacon->multiple_bssid.cnt;
308 + if (ema_index != IEEE80211_BCN_EMA_NONE &&
309 + ema_index >= beacon->multiple_bssid.cnt)
312 + if (beacon->multiple_bssid.cnt) {
313 + if (ema_index >= IEEE80211_BCN_EMA_INDEX) {
314 + multiple_bssid_len = beacon->multiple_bssid.len[ema_index];
318 + for (i = 0; i < beacon->multiple_bssid.cnt; i++)
319 + multiple_bssid_len = beacon->multiple_bssid.len[i];
324 * headroom, head length,
325 * tail length and maximum TIM length
326 @@ -4765,9 +4801,10 @@ __ieee80211_beacon_get(struct ieee80211_
327 skb = dev_alloc_skb(local->tx_headroom +
329 beacon->tail_len + 256 +
330 - local->hw.extra_beacon_tailroom);
331 + local->hw.extra_beacon_tailroom +
332 + multiple_bssid_len);
337 skb_reserve(skb, local->tx_headroom);
338 skb_put_data(skb, beacon->head, beacon->head_len);
339 @@ -4783,21 +4820,38 @@ __ieee80211_beacon_get(struct ieee80211_
340 csa_off_base = skb->len;
343 + if (multiple_bssid_len) {
344 + if (ema_index >= IEEE80211_BCN_EMA_INDEX) {
345 + ieee80211_beacon_add_multiple_bssid_config(vif, skb,
346 + &beacon->multiple_bssid);
347 + skb_put_data(skb, beacon->multiple_bssid.ies[beacon->ema_index],
348 + beacon->multiple_bssid.len[beacon->ema_index]);
352 + for (i = 0; i < beacon->multiple_bssid.cnt; i++)
353 + skb_put_data(skb, beacon->multiple_bssid.ies[i],
354 + beacon->multiple_bssid.len[i]);
357 + offs->multiple_bssid_offset = skb->len - multiple_bssid_len;
361 skb_put_data(skb, beacon->tail,
364 if (ieee80211_beacon_protect(skb, local, sdata) < 0)
370 } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
371 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
372 struct ieee80211_hdr *hdr;
374 beacon = rcu_dereference(ifibss->presp);
379 if (beacon->csa_counter_offsets[0]) {
381 @@ -4809,7 +4863,7 @@ __ieee80211_beacon_get(struct ieee80211_
382 skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
383 local->hw.extra_beacon_tailroom);
387 skb_reserve(skb, local->tx_headroom);
388 skb_put_data(skb, beacon->head, beacon->head_len);
390 @@ -4821,7 +4875,7 @@ __ieee80211_beacon_get(struct ieee80211_
392 beacon = rcu_dereference(ifmsh->beacon);
397 if (beacon->csa_counter_offsets[0]) {
399 @@ -4844,7 +4898,7 @@ __ieee80211_beacon_get(struct ieee80211_
401 local->hw.extra_beacon_tailroom);
405 skb_reserve(skb, local->tx_headroom);
406 skb_put_data(skb, beacon->head, beacon->head_len);
407 ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template);
408 @@ -4857,7 +4911,7 @@ __ieee80211_beacon_get(struct ieee80211_
409 skb_put_data(skb, beacon->tail, beacon->tail_len);
417 @@ -4900,8 +4954,6 @@ __ieee80211_beacon_get(struct ieee80211_
418 info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT |
419 IEEE80211_TX_CTL_ASSIGN_SEQ |
420 IEEE80211_TX_CTL_FIRST_FRAGMENT;
426 @@ -4911,16 +4963,86 @@ ieee80211_beacon_get_template(struct iee
427 struct ieee80211_vif *vif,
428 struct ieee80211_mutable_offsets *offs)
430 - return __ieee80211_beacon_get(hw, vif, offs, true);
431 + struct sk_buff *bcn;
434 + bcn = __ieee80211_beacon_get(hw, vif, offs, true,
435 + IEEE80211_BCN_EMA_NONE);
440 EXPORT_SYMBOL(ieee80211_beacon_get_template);
443 +ieee80211_beacon_get_template_ema_next(struct ieee80211_hw *hw,
444 + struct ieee80211_vif *vif,
445 + struct ieee80211_mutable_offsets *offs)
447 + struct sk_buff *bcn;
450 + bcn = __ieee80211_beacon_get(hw, vif, offs, true,
451 + IEEE80211_BCN_EMA_NEXT);
456 +EXPORT_SYMBOL(ieee80211_beacon_get_template_ema_next);
459 +ieee80211_beacon_free_ema_list(struct list_head *head)
461 + struct ieee80211_ema_bcn_list *ema, *tmp;
463 + list_for_each_entry_safe(ema, tmp, head, list) {
464 + kfree_skb(ema->skb);
468 +EXPORT_SYMBOL(ieee80211_beacon_free_ema_list);
471 +ieee80211_beacon_get_template_ema_list(struct ieee80211_hw *hw,
472 + struct ieee80211_vif *vif,
473 + struct list_head *head)
479 + struct ieee80211_ema_bcn_list *ema;
481 + ema = kmalloc(sizeof(*ema), GFP_KERNEL);
483 + ieee80211_beacon_free_ema_list(head);
488 + ema->skb = __ieee80211_beacon_get(hw, vif, &ema->offs, true,
494 + list_add_tail(&ema->list, head);
502 +EXPORT_SYMBOL(ieee80211_beacon_get_template_ema_list);
504 struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
505 struct ieee80211_vif *vif,
506 u16 *tim_offset, u16 *tim_length)
508 struct ieee80211_mutable_offsets offs = {};
509 - struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false);
510 + struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false,
511 + IEEE80211_BCN_EMA_NONE);
512 struct sk_buff *copy;
513 struct ieee80211_supported_band *sband;