1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright 2012-2013, Marco Porsch <marco.porsch@s2005.tu-chemnitz.de> |
4 | * Copyright 2012-2013, cozybit Inc. |
5 | * Copyright (C) 2021 Intel Corporation |
6 | * Copyright (C) 2023 Intel Corporation |
7 | */ |
8 | |
9 | #include "mesh.h" |
10 | #include "wme.h" |
11 | |
12 | |
13 | /* mesh PS management */ |
14 | |
15 | /** |
16 | * mps_qos_null_get - create pre-addressed QoS Null frame for mesh powersave |
17 | * @sta: the station to get the frame for |
18 | * |
19 | * Returns: A newly allocated SKB |
20 | */ |
21 | static struct sk_buff *mps_qos_null_get(struct sta_info *sta) |
22 | { |
23 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
24 | struct ieee80211_local *local = sdata->local; |
25 | struct ieee80211_hdr *nullfunc; /* use 4addr header */ |
26 | struct sk_buff *skb; |
27 | int size = sizeof(*nullfunc); |
28 | __le16 fc; |
29 | |
30 | skb = dev_alloc_skb(length: local->hw.extra_tx_headroom + size + 2); |
31 | if (!skb) |
32 | return NULL; |
33 | skb_reserve(skb, len: local->hw.extra_tx_headroom); |
34 | |
35 | nullfunc = skb_put(skb, len: size); |
36 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC); |
37 | ieee80211_fill_mesh_addresses(hdr: nullfunc, fc: &fc, da: sta->sta.addr, |
38 | sa: sdata->vif.addr); |
39 | nullfunc->frame_control = fc; |
40 | nullfunc->duration_id = 0; |
41 | nullfunc->seq_ctrl = 0; |
42 | /* no address resolution for this frame -> set addr 1 immediately */ |
43 | memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN); |
44 | skb_put_zero(skb, len: 2); /* append QoS control field */ |
45 | ieee80211_mps_set_frame_flags(sdata, sta, hdr: nullfunc); |
46 | |
47 | return skb; |
48 | } |
49 | |
50 | /** |
51 | * mps_qos_null_tx - send a QoS Null to indicate link-specific power mode |
52 | * @sta: the station to send to |
53 | */ |
54 | static void mps_qos_null_tx(struct sta_info *sta) |
55 | { |
56 | struct sk_buff *skb; |
57 | |
58 | skb = mps_qos_null_get(sta); |
59 | if (!skb) |
60 | return; |
61 | |
62 | mps_dbg(sta->sdata, "announcing peer-specific power mode to %pM\n" , |
63 | sta->sta.addr); |
64 | |
65 | /* don't unintentionally start a MPSP */ |
66 | if (!test_sta_flag(sta, flag: WLAN_STA_PS_STA)) { |
67 | u8 *qc = ieee80211_get_qos_ctl(hdr: (void *) skb->data); |
68 | |
69 | qc[0] |= IEEE80211_QOS_CTL_EOSP; |
70 | } |
71 | |
72 | ieee80211_tx_skb(sdata: sta->sdata, skb); |
73 | } |
74 | |
75 | /** |
76 | * ieee80211_mps_local_status_update - track status of local link-specific PMs |
77 | * |
78 | * @sdata: local mesh subif |
79 | * |
80 | * sets the non-peer power mode and triggers the driver PS (re-)configuration |
81 | * Return BSS_CHANGED_BEACON if a beacon update is necessary. |
82 | * |
83 | * Returns: BSS_CHANGED_BEACON if a beacon update is in order. |
84 | */ |
85 | u64 ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata) |
86 | { |
87 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
88 | struct sta_info *sta; |
89 | bool peering = false; |
90 | int light_sleep_cnt = 0; |
91 | int deep_sleep_cnt = 0; |
92 | u64 changed = 0; |
93 | enum nl80211_mesh_power_mode nonpeer_pm; |
94 | |
95 | rcu_read_lock(); |
96 | list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { |
97 | if (sdata != sta->sdata) |
98 | continue; |
99 | |
100 | switch (sta->mesh->plink_state) { |
101 | case NL80211_PLINK_OPN_SNT: |
102 | case NL80211_PLINK_OPN_RCVD: |
103 | case NL80211_PLINK_CNF_RCVD: |
104 | peering = true; |
105 | break; |
106 | case NL80211_PLINK_ESTAB: |
107 | if (sta->mesh->local_pm == NL80211_MESH_POWER_LIGHT_SLEEP) |
108 | light_sleep_cnt++; |
109 | else if (sta->mesh->local_pm == NL80211_MESH_POWER_DEEP_SLEEP) |
110 | deep_sleep_cnt++; |
111 | break; |
112 | default: |
113 | break; |
114 | } |
115 | } |
116 | rcu_read_unlock(); |
117 | |
118 | /* |
119 | * Set non-peer mode to active during peering/scanning/authentication |
120 | * (see IEEE802.11-2012 13.14.8.3). The non-peer mesh power mode is |
121 | * deep sleep if the local STA is in light or deep sleep towards at |
122 | * least one mesh peer (see 13.14.3.1). Otherwise, set it to the |
123 | * user-configured default value. |
124 | */ |
125 | if (peering) { |
126 | mps_dbg(sdata, "setting non-peer PM to active for peering\n" ); |
127 | nonpeer_pm = NL80211_MESH_POWER_ACTIVE; |
128 | } else if (light_sleep_cnt || deep_sleep_cnt) { |
129 | mps_dbg(sdata, "setting non-peer PM to deep sleep\n" ); |
130 | nonpeer_pm = NL80211_MESH_POWER_DEEP_SLEEP; |
131 | } else { |
132 | mps_dbg(sdata, "setting non-peer PM to user value\n" ); |
133 | nonpeer_pm = ifmsh->mshcfg.power_mode; |
134 | } |
135 | |
136 | /* need update if sleep counts move between 0 and non-zero */ |
137 | if (ifmsh->nonpeer_pm != nonpeer_pm || |
138 | !ifmsh->ps_peers_light_sleep != !light_sleep_cnt || |
139 | !ifmsh->ps_peers_deep_sleep != !deep_sleep_cnt) |
140 | changed = BSS_CHANGED_BEACON; |
141 | |
142 | ifmsh->nonpeer_pm = nonpeer_pm; |
143 | ifmsh->ps_peers_light_sleep = light_sleep_cnt; |
144 | ifmsh->ps_peers_deep_sleep = deep_sleep_cnt; |
145 | |
146 | return changed; |
147 | } |
148 | |
149 | /** |
150 | * ieee80211_mps_set_sta_local_pm - set local PM towards a mesh STA |
151 | * |
152 | * @sta: mesh STA |
153 | * @pm: the power mode to set |
154 | * Returns: BSS_CHANGED_BEACON if a beacon update is in order. |
155 | */ |
156 | u64 ieee80211_mps_set_sta_local_pm(struct sta_info *sta, |
157 | enum nl80211_mesh_power_mode pm) |
158 | { |
159 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
160 | |
161 | if (sta->mesh->local_pm == pm) |
162 | return 0; |
163 | |
164 | mps_dbg(sdata, "local STA operates in mode %d with %pM\n" , |
165 | pm, sta->sta.addr); |
166 | |
167 | sta->mesh->local_pm = pm; |
168 | |
169 | /* |
170 | * announce peer-specific power mode transition |
171 | * (see IEEE802.11-2012 13.14.3.2 and 13.14.3.3) |
172 | */ |
173 | if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) |
174 | mps_qos_null_tx(sta); |
175 | |
176 | return ieee80211_mps_local_status_update(sdata); |
177 | } |
178 | |
179 | /** |
180 | * ieee80211_mps_set_frame_flags - set mesh PS flags in FC (and QoS Control) |
181 | * |
182 | * @sdata: local mesh subif |
183 | * @sta: mesh STA |
184 | * @hdr: 802.11 frame header |
185 | * |
186 | * see IEEE802.11-2012 8.2.4.1.7 and 8.2.4.5.11 |
187 | * |
188 | * NOTE: sta must be given when an individually-addressed QoS frame header |
189 | * is handled, for group-addressed and management frames it is not used |
190 | */ |
191 | void ieee80211_mps_set_frame_flags(struct ieee80211_sub_if_data *sdata, |
192 | struct sta_info *sta, |
193 | struct ieee80211_hdr *hdr) |
194 | { |
195 | enum nl80211_mesh_power_mode pm; |
196 | u8 *qc; |
197 | |
198 | if (WARN_ON(is_unicast_ether_addr(hdr->addr1) && |
199 | ieee80211_is_data_qos(hdr->frame_control) && |
200 | !sta)) |
201 | return; |
202 | |
203 | if (is_unicast_ether_addr(addr: hdr->addr1) && |
204 | ieee80211_is_data_qos(fc: hdr->frame_control) && |
205 | sta->mesh->plink_state == NL80211_PLINK_ESTAB) |
206 | pm = sta->mesh->local_pm; |
207 | else |
208 | pm = sdata->u.mesh.nonpeer_pm; |
209 | |
210 | if (pm == NL80211_MESH_POWER_ACTIVE) |
211 | hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_PM); |
212 | else |
213 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); |
214 | |
215 | if (!ieee80211_is_data_qos(fc: hdr->frame_control)) |
216 | return; |
217 | |
218 | qc = ieee80211_get_qos_ctl(hdr); |
219 | |
220 | if ((is_unicast_ether_addr(addr: hdr->addr1) && |
221 | pm == NL80211_MESH_POWER_DEEP_SLEEP) || |
222 | (is_multicast_ether_addr(addr: hdr->addr1) && |
223 | sdata->u.mesh.ps_peers_deep_sleep > 0)) |
224 | qc[1] |= (IEEE80211_QOS_CTL_MESH_PS_LEVEL >> 8); |
225 | else |
226 | qc[1] &= ~(IEEE80211_QOS_CTL_MESH_PS_LEVEL >> 8); |
227 | } |
228 | |
229 | /** |
230 | * ieee80211_mps_sta_status_update - update buffering status of neighbor STA |
231 | * |
232 | * @sta: mesh STA |
233 | * |
234 | * called after change of peering status or non-peer/peer-specific power mode |
235 | */ |
236 | void ieee80211_mps_sta_status_update(struct sta_info *sta) |
237 | { |
238 | enum nl80211_mesh_power_mode pm; |
239 | bool do_buffer; |
240 | |
241 | /* For non-assoc STA, prevent buffering or frame transmission */ |
242 | if (sta->sta_state < IEEE80211_STA_ASSOC) |
243 | return; |
244 | |
245 | /* |
246 | * use peer-specific power mode if peering is established and the |
247 | * peer's power mode is known |
248 | */ |
249 | if (sta->mesh->plink_state == NL80211_PLINK_ESTAB && |
250 | sta->mesh->peer_pm != NL80211_MESH_POWER_UNKNOWN) |
251 | pm = sta->mesh->peer_pm; |
252 | else |
253 | pm = sta->mesh->nonpeer_pm; |
254 | |
255 | do_buffer = (pm != NL80211_MESH_POWER_ACTIVE); |
256 | |
257 | /* clear the MPSP flags for non-peers or active STA */ |
258 | if (sta->mesh->plink_state != NL80211_PLINK_ESTAB) { |
259 | clear_sta_flag(sta, flag: WLAN_STA_MPSP_OWNER); |
260 | clear_sta_flag(sta, flag: WLAN_STA_MPSP_RECIPIENT); |
261 | } else if (!do_buffer) { |
262 | clear_sta_flag(sta, flag: WLAN_STA_MPSP_OWNER); |
263 | } |
264 | |
265 | /* Don't let the same PS state be set twice */ |
266 | if (test_sta_flag(sta, flag: WLAN_STA_PS_STA) == do_buffer) |
267 | return; |
268 | |
269 | if (do_buffer) { |
270 | set_sta_flag(sta, flag: WLAN_STA_PS_STA); |
271 | atomic_inc(v: &sta->sdata->u.mesh.ps.num_sta_ps); |
272 | mps_dbg(sta->sdata, "start PS buffering frames towards %pM\n" , |
273 | sta->sta.addr); |
274 | } else { |
275 | ieee80211_sta_ps_deliver_wakeup(sta); |
276 | } |
277 | } |
278 | |
279 | static void mps_set_sta_peer_pm(struct sta_info *sta, |
280 | struct ieee80211_hdr *hdr) |
281 | { |
282 | enum nl80211_mesh_power_mode pm; |
283 | u8 *qc = ieee80211_get_qos_ctl(hdr); |
284 | |
285 | /* |
286 | * Test Power Management field of frame control (PW) and |
287 | * mesh power save level subfield of QoS control field (PSL) |
288 | * |
289 | * | PM | PSL| Mesh PM | |
290 | * +----+----+---------+ |
291 | * | 0 |Rsrv| Active | |
292 | * | 1 | 0 | Light | |
293 | * | 1 | 1 | Deep | |
294 | */ |
295 | if (ieee80211_has_pm(fc: hdr->frame_control)) { |
296 | if (qc[1] & (IEEE80211_QOS_CTL_MESH_PS_LEVEL >> 8)) |
297 | pm = NL80211_MESH_POWER_DEEP_SLEEP; |
298 | else |
299 | pm = NL80211_MESH_POWER_LIGHT_SLEEP; |
300 | } else { |
301 | pm = NL80211_MESH_POWER_ACTIVE; |
302 | } |
303 | |
304 | if (sta->mesh->peer_pm == pm) |
305 | return; |
306 | |
307 | mps_dbg(sta->sdata, "STA %pM enters mode %d\n" , |
308 | sta->sta.addr, pm); |
309 | |
310 | sta->mesh->peer_pm = pm; |
311 | |
312 | ieee80211_mps_sta_status_update(sta); |
313 | } |
314 | |
315 | static void mps_set_sta_nonpeer_pm(struct sta_info *sta, |
316 | struct ieee80211_hdr *hdr) |
317 | { |
318 | enum nl80211_mesh_power_mode pm; |
319 | |
320 | if (ieee80211_has_pm(fc: hdr->frame_control)) |
321 | pm = NL80211_MESH_POWER_DEEP_SLEEP; |
322 | else |
323 | pm = NL80211_MESH_POWER_ACTIVE; |
324 | |
325 | if (sta->mesh->nonpeer_pm == pm) |
326 | return; |
327 | |
328 | mps_dbg(sta->sdata, "STA %pM sets non-peer mode to %d\n" , |
329 | sta->sta.addr, pm); |
330 | |
331 | sta->mesh->nonpeer_pm = pm; |
332 | |
333 | ieee80211_mps_sta_status_update(sta); |
334 | } |
335 | |
336 | /** |
337 | * ieee80211_mps_rx_h_sta_process - frame receive handler for mesh powersave |
338 | * |
339 | * @sta: STA info that transmitted the frame |
340 | * @hdr: IEEE 802.11 (QoS) Header |
341 | */ |
342 | void ieee80211_mps_rx_h_sta_process(struct sta_info *sta, |
343 | struct ieee80211_hdr *hdr) |
344 | { |
345 | if (is_unicast_ether_addr(addr: hdr->addr1) && |
346 | ieee80211_is_data_qos(fc: hdr->frame_control)) { |
347 | /* |
348 | * individually addressed QoS Data/Null frames contain |
349 | * peer link-specific PS mode towards the local STA |
350 | */ |
351 | mps_set_sta_peer_pm(sta, hdr); |
352 | |
353 | /* check for mesh Peer Service Period trigger frames */ |
354 | ieee80211_mpsp_trigger_process(qc: ieee80211_get_qos_ctl(hdr), |
355 | sta, tx: false, acked: false); |
356 | } else { |
357 | /* |
358 | * can only determine non-peer PS mode |
359 | * (see IEEE802.11-2012 8.2.4.1.7) |
360 | */ |
361 | mps_set_sta_nonpeer_pm(sta, hdr); |
362 | } |
363 | } |
364 | |
365 | |
366 | /* mesh PS frame release */ |
367 | |
368 | static void mpsp_trigger_send(struct sta_info *sta, bool rspi, bool eosp) |
369 | { |
370 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
371 | struct sk_buff *skb; |
372 | struct ieee80211_hdr *nullfunc; |
373 | struct ieee80211_tx_info *info; |
374 | u8 *qc; |
375 | |
376 | skb = mps_qos_null_get(sta); |
377 | if (!skb) |
378 | return; |
379 | |
380 | nullfunc = (struct ieee80211_hdr *) skb->data; |
381 | if (!eosp) |
382 | nullfunc->frame_control |= |
383 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); |
384 | /* |
385 | * | RSPI | EOSP | MPSP triggering | |
386 | * +------+------+--------------------+ |
387 | * | 0 | 0 | local STA is owner | |
388 | * | 0 | 1 | no MPSP (MPSP end) | |
389 | * | 1 | 0 | both STA are owner | |
390 | * | 1 | 1 | peer STA is owner | see IEEE802.11-2012 13.14.9.2 |
391 | */ |
392 | qc = ieee80211_get_qos_ctl(hdr: nullfunc); |
393 | if (rspi) |
394 | qc[1] |= (IEEE80211_QOS_CTL_RSPI >> 8); |
395 | if (eosp) |
396 | qc[0] |= IEEE80211_QOS_CTL_EOSP; |
397 | |
398 | info = IEEE80211_SKB_CB(skb); |
399 | |
400 | info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER | |
401 | IEEE80211_TX_CTL_REQ_TX_STATUS; |
402 | |
403 | mps_dbg(sdata, "sending MPSP trigger%s%s to %pM\n" , |
404 | rspi ? " RSPI" : "" , eosp ? " EOSP" : "" , sta->sta.addr); |
405 | |
406 | ieee80211_tx_skb(sdata, skb); |
407 | } |
408 | |
409 | /** |
410 | * mpsp_qos_null_append - append QoS Null frame to MPSP skb queue if needed |
411 | * @sta: the station to handle |
412 | * @frames: the frame list to append to |
413 | * |
414 | * To properly end a mesh MPSP the last transmitted frame has to set the EOSP |
415 | * flag in the QoS Control field. In case the current tailing frame is not a |
416 | * QoS Data frame, append a QoS Null to carry the flag. |
417 | */ |
418 | static void mpsp_qos_null_append(struct sta_info *sta, |
419 | struct sk_buff_head *frames) |
420 | { |
421 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
422 | struct sk_buff *new_skb, *skb = skb_peek_tail(list_: frames); |
423 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
424 | struct ieee80211_tx_info *info; |
425 | |
426 | if (ieee80211_is_data_qos(fc: hdr->frame_control)) |
427 | return; |
428 | |
429 | new_skb = mps_qos_null_get(sta); |
430 | if (!new_skb) |
431 | return; |
432 | |
433 | mps_dbg(sdata, "appending QoS Null in MPSP towards %pM\n" , |
434 | sta->sta.addr); |
435 | /* |
436 | * This frame has to be transmitted last. Assign lowest priority to |
437 | * make sure it cannot pass other frames when releasing multiple ACs. |
438 | */ |
439 | new_skb->priority = 1; |
440 | skb_set_queue_mapping(skb: new_skb, queue_mapping: IEEE80211_AC_BK); |
441 | ieee80211_set_qos_hdr(sdata, skb: new_skb); |
442 | |
443 | info = IEEE80211_SKB_CB(skb: new_skb); |
444 | info->control.vif = &sdata->vif; |
445 | info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING; |
446 | |
447 | __skb_queue_tail(list: frames, newsk: new_skb); |
448 | } |
449 | |
450 | /** |
451 | * mps_frame_deliver - transmit frames during mesh powersave |
452 | * |
453 | * @sta: STA info to transmit to |
454 | * @n_frames: number of frames to transmit. -1 for all |
455 | */ |
456 | static void mps_frame_deliver(struct sta_info *sta, int n_frames) |
457 | { |
458 | struct ieee80211_local *local = sta->sdata->local; |
459 | int ac; |
460 | struct sk_buff_head frames; |
461 | struct sk_buff *skb; |
462 | bool more_data = false; |
463 | |
464 | skb_queue_head_init(list: &frames); |
465 | |
466 | /* collect frame(s) from buffers */ |
467 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { |
468 | while (n_frames != 0) { |
469 | skb = skb_dequeue(list: &sta->tx_filtered[ac]); |
470 | if (!skb) { |
471 | skb = skb_dequeue( |
472 | list: &sta->ps_tx_buf[ac]); |
473 | if (skb) |
474 | local->total_ps_buffered--; |
475 | } |
476 | if (!skb) |
477 | break; |
478 | n_frames--; |
479 | __skb_queue_tail(list: &frames, newsk: skb); |
480 | } |
481 | |
482 | if (!skb_queue_empty(list: &sta->tx_filtered[ac]) || |
483 | !skb_queue_empty(list: &sta->ps_tx_buf[ac])) |
484 | more_data = true; |
485 | } |
486 | |
487 | /* nothing to send? -> EOSP */ |
488 | if (skb_queue_empty(list: &frames)) { |
489 | mpsp_trigger_send(sta, rspi: false, eosp: true); |
490 | return; |
491 | } |
492 | |
493 | /* in a MPSP make sure the last skb is a QoS Data frame */ |
494 | if (test_sta_flag(sta, flag: WLAN_STA_MPSP_OWNER)) |
495 | mpsp_qos_null_append(sta, frames: &frames); |
496 | |
497 | mps_dbg(sta->sdata, "sending %d frames to PS STA %pM\n" , |
498 | skb_queue_len(&frames), sta->sta.addr); |
499 | |
500 | /* prepare collected frames for transmission */ |
501 | skb_queue_walk(&frames, skb) { |
502 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
503 | struct ieee80211_hdr *hdr = (void *) skb->data; |
504 | |
505 | /* |
506 | * Tell TX path to send this frame even though the |
507 | * STA may still remain is PS mode after this frame |
508 | * exchange. |
509 | */ |
510 | info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; |
511 | |
512 | if (more_data || !skb_queue_is_last(list: &frames, skb)) |
513 | hdr->frame_control |= |
514 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); |
515 | else |
516 | hdr->frame_control &= |
517 | cpu_to_le16(~IEEE80211_FCTL_MOREDATA); |
518 | |
519 | if (skb_queue_is_last(list: &frames, skb) && |
520 | ieee80211_is_data_qos(fc: hdr->frame_control)) { |
521 | u8 *qoshdr = ieee80211_get_qos_ctl(hdr); |
522 | |
523 | /* MPSP trigger frame ends service period */ |
524 | *qoshdr |= IEEE80211_QOS_CTL_EOSP; |
525 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; |
526 | } |
527 | } |
528 | |
529 | ieee80211_add_pending_skbs(local, skbs: &frames); |
530 | sta_info_recalc_tim(sta); |
531 | } |
532 | |
533 | /** |
534 | * ieee80211_mpsp_trigger_process - track status of mesh Peer Service Periods |
535 | * |
536 | * @qc: QoS Control field |
537 | * @sta: peer to start a MPSP with |
538 | * @tx: frame was transmitted by the local STA |
539 | * @acked: frame has been transmitted successfully |
540 | * |
541 | * NOTE: active mode STA may only serve as MPSP owner |
542 | */ |
543 | void ieee80211_mpsp_trigger_process(u8 *qc, struct sta_info *sta, |
544 | bool tx, bool acked) |
545 | { |
546 | u8 rspi = qc[1] & (IEEE80211_QOS_CTL_RSPI >> 8); |
547 | u8 eosp = qc[0] & IEEE80211_QOS_CTL_EOSP; |
548 | |
549 | if (tx) { |
550 | if (rspi && acked) |
551 | set_sta_flag(sta, flag: WLAN_STA_MPSP_RECIPIENT); |
552 | |
553 | if (eosp) |
554 | clear_sta_flag(sta, flag: WLAN_STA_MPSP_OWNER); |
555 | else if (acked && |
556 | test_sta_flag(sta, flag: WLAN_STA_PS_STA) && |
557 | !test_and_set_sta_flag(sta, flag: WLAN_STA_MPSP_OWNER)) |
558 | mps_frame_deliver(sta, n_frames: -1); |
559 | } else { |
560 | if (eosp) |
561 | clear_sta_flag(sta, flag: WLAN_STA_MPSP_RECIPIENT); |
562 | else if (sta->mesh->local_pm != NL80211_MESH_POWER_ACTIVE) |
563 | set_sta_flag(sta, flag: WLAN_STA_MPSP_RECIPIENT); |
564 | |
565 | if (rspi && !test_and_set_sta_flag(sta, flag: WLAN_STA_MPSP_OWNER)) |
566 | mps_frame_deliver(sta, n_frames: -1); |
567 | } |
568 | } |
569 | |
570 | /** |
571 | * ieee80211_mps_frame_release - release frames buffered due to mesh power save |
572 | * |
573 | * @sta: mesh STA |
574 | * @elems: IEs of beacon or probe response |
575 | * |
576 | * For peers if we have individually-addressed frames buffered or the peer |
577 | * indicates buffered frames, send a corresponding MPSP trigger frame. Since |
578 | * we do not evaluate the awake window duration, QoS Nulls are used as MPSP |
579 | * trigger frames. If the neighbour STA is not a peer, only send single frames. |
580 | */ |
581 | void ieee80211_mps_frame_release(struct sta_info *sta, |
582 | struct ieee802_11_elems *elems) |
583 | { |
584 | int ac, buffer_local = 0; |
585 | bool has_buffered = false; |
586 | |
587 | if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) |
588 | has_buffered = ieee80211_check_tim(tim: elems->tim, tim_len: elems->tim_len, |
589 | aid: sta->mesh->aid); |
590 | |
591 | if (has_buffered) |
592 | mps_dbg(sta->sdata, "%pM indicates buffered frames\n" , |
593 | sta->sta.addr); |
594 | |
595 | /* only transmit to PS STA with announced, non-zero awake window */ |
596 | if (test_sta_flag(sta, flag: WLAN_STA_PS_STA) && |
597 | (!elems->awake_window || !get_unaligned_le16(p: elems->awake_window))) |
598 | return; |
599 | |
600 | if (!test_sta_flag(sta, flag: WLAN_STA_MPSP_OWNER)) |
601 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) |
602 | buffer_local += skb_queue_len(list_: &sta->ps_tx_buf[ac]) + |
603 | skb_queue_len(list_: &sta->tx_filtered[ac]); |
604 | |
605 | if (!has_buffered && !buffer_local) |
606 | return; |
607 | |
608 | if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) |
609 | mpsp_trigger_send(sta, rspi: has_buffered, eosp: !buffer_local); |
610 | else |
611 | mps_frame_deliver(sta, n_frames: 1); |
612 | } |
613 | |