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