mac80211: add multiple bssid support
[openwrt/staging/blogic.git] / package / kernel / mac80211 / patches / subsys / 602-mac80211-add-multiple-bssid-EMA-support-to-beacon-ha.patch
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
5 handling
6
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
9 code paths.
10
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.
14
15 Signed-off-by: John Crispin <john@phrozen.org>
16 ---
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(-)
22
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 {
28 u16 tim_length;
29
30 u16 csa_counter_offs[IEEE80211_MAX_CSA_COUNTERS_NUM];
31 + u16 multiple_bssid_offset;
32 + u16 multiple_bssid_length;
33 };
34
35 /**
36 @@ -4861,6 +4863,91 @@ ieee80211_beacon_get_template(struct iee
37 struct ieee80211_mutable_offsets *offs);
38
39 /**
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.
45 + */
46 +enum ieee80211_bcn_tmpl_ema {
47 + IEEE80211_BCN_EMA_NONE = -2,
48 + IEEE80211_BCN_EMA_NEXT = -1,
49 + IEEE80211_BCN_EMA_INDEX = 0,
50 +};
51 +
52 +/**
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.
59 + *
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.
65 + *
66 + * This function needs to follow the same rules as ieee80211_beacon_get_template
67 + *
68 + * Return: The beacon template. %NULL on error.
69 + */
70 +
71 +struct sk_buff *
72 +ieee80211_beacon_get_template_ema_next(struct ieee80211_hw *hw,
73 + struct ieee80211_vif *vif,
74 + struct ieee80211_mutable_offsets *offs);
75 +
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.
81 + */
82 +struct ieee80211_ema_bcn_list {
83 + struct list_head list;
84 + struct sk_buff * skb;
85 + struct ieee80211_mutable_offsets offs;
86 +};
87 +
88 +/**
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.
95 + *
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
101 + * to the HW.
102 + *
103 + * This function needs to follow the same rules as ieee80211_beacon_get_template
104 + *
105 + * Return: The nuber of entries in the list or 0 on error.
106 + */
107 +
108 +int
109 +ieee80211_beacon_get_template_ema_list(struct ieee80211_hw *hw,
110 + struct ieee80211_vif *vif,
111 + struct list_head *head);
112 +
113 +/**
114 + * ieee80211_beacon_free_ema_list - free an EMA beacon template list
115 + * @head: linked list head containing &struct ieee80211_ema_bcn_list pointers.
116 + *
117 + * This function will free a list previously acquired by calling
118 + * ieee80211_beacon_get_template_ema_list()
119 + */
120 +
121 +void
122 +ieee80211_beacon_free_ema_list(struct list_head *head);
123 +
124 +/**
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
133 return 0;
134 }
135
136 +static int ieee80211_get_multiple_bssid_beacon_len(struct cfg80211_multiple_bssid_data *data)
137 +{
138 + int i, len = 0;
139 +
140 + for (i = 0; i < data->cnt; i++)
141 + len += data->len[i];
142 +
143 + return len;
144 +}
145 +
146 +static u8 *ieee80211_copy_multiple_bssid_beacon(u8 *offset,
147 + struct cfg80211_multiple_bssid_data *new,
148 + struct cfg80211_multiple_bssid_data *old)
149 +{
150 + int i;
151 +
152 + *new = *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];
157 + }
158 + return offset;
159 +}
160 +
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)
164 {
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;
169 int size, err;
170 u32 changed = BSS_CHANGED_BEACON;
171
172 @@ -958,7 +984,15 @@ static int ieee80211_assign_beacon(struc
173 else
174 new_tail_len = old->tail_len;
175
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(&params->multiple_bssid);
181 + else
182 + new_multiple_bssid_len =
183 + ieee80211_get_multiple_bssid_beacon_len(&old->multiple_bssid);
184 +
185 + size = sizeof(*new) + new_head_len + new_tail_len + new_multiple_bssid_len;
186
187 new = kzalloc(size, GFP_KERNEL);
188 if (!new)
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;
192
193 + new_multiple_bssid_offset = new->tail + new_tail_len;
194 +
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 + &params->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);
204 +
205 if (csa) {
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
209
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);
215
216 new_beacon = kzalloc(sizeof(*new_beacon) + len, GFP_KERNEL);
217 if (!new_beacon)
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;
221 }
222 + if (beacon->multiple_bssid.cnt)
223 + pos = ieee80211_copy_multiple_bssid_beacon(pos,
224 + &new_beacon->multiple_bssid,
225 + &beacon->multiple_bssid);
226
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;
238 + u16 ema_index;
239 struct rcu_head rcu_head;
240 };
241
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
247 return 0;
248 }
249
250 +static void
251 +ieee80211_beacon_add_multiple_bssid_config(struct ieee80211_vif *vif, struct sk_buff *skb,
252 + struct cfg80211_multiple_bssid_data *config)
253 +{
254 + u8 *pos = skb_put(skb, 6);
255 +
256 + *pos++ = WLAN_EID_EXTENSION;
257 + *pos++ = 4;
258 + *pos++ = WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION;
259 + *pos++ = 2;
260 + *pos++ = vif->bss_conf.multiple_bssid.count;
261 + *pos++ = config->cnt;
262 +}
263 +
264 static struct sk_buff *
265 __ieee80211_beacon_get(struct ieee80211_hw *hw,
266 struct ieee80211_vif *vif,
267 struct ieee80211_mutable_offsets *offs,
268 - bool is_template)
269 + bool is_template,
270 + int ema_index)
271 {
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;
277
278 - rcu_read_lock();
279 -
280 sdata = vif_to_sdata(vif);
281 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
282
283 if (!ieee80211_sdata_running(sdata) || !chanctx_conf)
284 - goto out;
285 + return NULL;
286
287 if (offs)
288 memset(offs, 0, sizeof(*offs));
289 @@ -4751,6 +4764,8 @@ __ieee80211_beacon_get(struct ieee80211_
290
291 beacon = rcu_dereference(ap->beacon);
292 if (beacon) {
293 + int multiple_bssid_len = 0;
294 +
295 if (beacon->csa_counter_offsets[0]) {
296 if (!is_template)
297 __ieee80211_csa_update_counter(beacon);
298 @@ -4758,6 +4773,27 @@ __ieee80211_beacon_get(struct ieee80211_
299 ieee80211_set_csa(sdata, beacon);
300 }
301
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;
306 + }
307 +
308 + if (ema_index != IEEE80211_BCN_EMA_NONE &&
309 + ema_index >= beacon->multiple_bssid.cnt)
310 + return NULL;
311 +
312 + if (beacon->multiple_bssid.cnt) {
313 + if (ema_index >= IEEE80211_BCN_EMA_INDEX) {
314 + multiple_bssid_len = beacon->multiple_bssid.len[ema_index];
315 + } else {
316 + int i;
317 +
318 + for (i = 0; i < beacon->multiple_bssid.cnt; i++)
319 + multiple_bssid_len = beacon->multiple_bssid.len[i];
320 + }
321 + }
322 +
323 /*
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 +
328 beacon->head_len +
329 beacon->tail_len + 256 +
330 - local->hw.extra_beacon_tailroom);
331 + local->hw.extra_beacon_tailroom +
332 + multiple_bssid_len);
333 if (!skb)
334 - goto out;
335 + return NULL;
336
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;
341 }
342
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]);
349 + } else {
350 + int i;
351 +
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]);
355 + }
356 + if (offs)
357 + offs->multiple_bssid_offset = skb->len - multiple_bssid_len;
358 + }
359 +
360 if (beacon->tail)
361 skb_put_data(skb, beacon->tail,
362 beacon->tail_len);
363
364 if (ieee80211_beacon_protect(skb, local, sdata) < 0)
365 - goto out;
366 + return NULL;
367 } else
368 - goto out;
369 + return NULL;
370 } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
371 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
372 struct ieee80211_hdr *hdr;
373
374 beacon = rcu_dereference(ifibss->presp);
375 if (!beacon)
376 - goto out;
377 + return NULL;
378
379 if (beacon->csa_counter_offsets[0]) {
380 if (!is_template)
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);
384 if (!skb)
385 - goto out;
386 + return NULL;
387 skb_reserve(skb, local->tx_headroom);
388 skb_put_data(skb, beacon->head, beacon->head_len);
389
390 @@ -4821,7 +4875,7 @@ __ieee80211_beacon_get(struct ieee80211_
391
392 beacon = rcu_dereference(ifmsh->beacon);
393 if (!beacon)
394 - goto out;
395 + return NULL;
396
397 if (beacon->csa_counter_offsets[0]) {
398 if (!is_template)
399 @@ -4844,7 +4898,7 @@ __ieee80211_beacon_get(struct ieee80211_
400 beacon->tail_len +
401 local->hw.extra_beacon_tailroom);
402 if (!skb)
403 - goto out;
404 + return NULL;
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);
410 } else {
411 WARN_ON(1);
412 - goto out;
413 + return NULL;
414 }
415
416 /* CSA offsets */
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;
421 - out:
422 - rcu_read_unlock();
423 return skb;
424
425 }
426 @@ -4911,16 +4963,86 @@ ieee80211_beacon_get_template(struct iee
427 struct ieee80211_vif *vif,
428 struct ieee80211_mutable_offsets *offs)
429 {
430 - return __ieee80211_beacon_get(hw, vif, offs, true);
431 + struct sk_buff *bcn;
432 +
433 + rcu_read_lock();
434 + bcn = __ieee80211_beacon_get(hw, vif, offs, true,
435 + IEEE80211_BCN_EMA_NONE);
436 + rcu_read_unlock();
437 +
438 + return bcn;
439 }
440 EXPORT_SYMBOL(ieee80211_beacon_get_template);
441
442 +struct sk_buff *
443 +ieee80211_beacon_get_template_ema_next(struct ieee80211_hw *hw,
444 + struct ieee80211_vif *vif,
445 + struct ieee80211_mutable_offsets *offs)
446 +{
447 + struct sk_buff *bcn;
448 +
449 + rcu_read_lock();
450 + bcn = __ieee80211_beacon_get(hw, vif, offs, true,
451 + IEEE80211_BCN_EMA_NEXT);
452 + rcu_read_unlock();
453 +
454 + return bcn;
455 +}
456 +EXPORT_SYMBOL(ieee80211_beacon_get_template_ema_next);
457 +
458 +void
459 +ieee80211_beacon_free_ema_list(struct list_head *head)
460 +{
461 + struct ieee80211_ema_bcn_list *ema, *tmp;
462 +
463 + list_for_each_entry_safe(ema, tmp, head, list) {
464 + kfree_skb(ema->skb);
465 + kfree(ema);
466 + }
467 +}
468 +EXPORT_SYMBOL(ieee80211_beacon_free_ema_list);
469 +
470 +int
471 +ieee80211_beacon_get_template_ema_list(struct ieee80211_hw *hw,
472 + struct ieee80211_vif *vif,
473 + struct list_head *head)
474 +{
475 + int cnt = 0;
476 +
477 + rcu_read_lock();
478 + while (true) {
479 + struct ieee80211_ema_bcn_list *ema;
480 +
481 + ema = kmalloc(sizeof(*ema), GFP_KERNEL);
482 + if (!ema) {
483 + ieee80211_beacon_free_ema_list(head);
484 + cnt = 0;
485 + goto out;
486 + }
487 +
488 + ema->skb = __ieee80211_beacon_get(hw, vif, &ema->offs, true,
489 + cnt);
490 + if (!ema->skb) {
491 + kfree(ema);
492 + break;
493 + }
494 + list_add_tail(&ema->list, head);
495 + cnt++;
496 + }
497 +out:
498 + rcu_read_unlock();
499 +
500 + return cnt;
501 +}
502 +EXPORT_SYMBOL(ieee80211_beacon_get_template_ema_list);
503 +
504 struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
505 struct ieee80211_vif *vif,
506 u16 *tim_offset, u16 *tim_length)
507 {
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;
514 int shift;