aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/linux/ieee80211.h8
-rw-r--r--net/mac80211/Kconfig11
-rw-r--r--net/mac80211/Makefile3
-rw-r--r--net/mac80211/cfg.c27
-rw-r--r--net/mac80211/debug.h10
-rw-r--r--net/mac80211/debugfs_netdev.c5
-rw-r--r--net/mac80211/debugfs_sta.c5
-rw-r--r--net/mac80211/ieee80211_i.h6
-rw-r--r--net/mac80211/mesh.c33
-rw-r--r--net/mac80211/mesh.h17
-rw-r--r--net/mac80211/mesh_hwmp.c7
-rw-r--r--net/mac80211/mesh_pathtbl.c1
-rw-r--r--net/mac80211/mesh_plink.c17
-rw-r--r--net/mac80211/mesh_ps.c585
-rw-r--r--net/mac80211/rx.c7
-rw-r--r--net/mac80211/sta_info.c20
-rw-r--r--net/mac80211/sta_info.h11
-rw-r--r--net/mac80211/status.c7
-rw-r--r--net/mac80211/tx.c31
-rw-r--r--net/mac80211/util.c4
-rw-r--r--net/mac80211/wme.c13
21 files changed, 811 insertions, 17 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 11c8bc87fdcb..7e8a498efe6d 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -151,6 +151,11 @@
151/* Mesh Control 802.11s */ 151/* Mesh Control 802.11s */
152#define IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT 0x0100 152#define IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT 0x0100
153 153
154/* Mesh Power Save Level */
155#define IEEE80211_QOS_CTL_MESH_PS_LEVEL 0x0200
156/* Mesh Receiver Service Period Initiated */
157#define IEEE80211_QOS_CTL_RSPI 0x0400
158
154/* U-APSD queue for WMM IEs sent by AP */ 159/* U-APSD queue for WMM IEs sent by AP */
155#define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD (1<<7) 160#define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD (1<<7)
156#define IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK 0x0f 161#define IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK 0x0f
@@ -675,11 +680,14 @@ struct ieee80211_meshconf_ie {
675 * @IEEE80211_MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs 680 * @IEEE80211_MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs
676 * @IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure 681 * @IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure
677 * is ongoing 682 * is ongoing
683 * @IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL: STA is in deep sleep mode or has
684 * neighbors in deep sleep mode
678 */ 685 */
679enum mesh_config_capab_flags { 686enum mesh_config_capab_flags {
680 IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS = 0x01, 687 IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS = 0x01,
681 IEEE80211_MESHCONF_CAPAB_FORWARDING = 0x08, 688 IEEE80211_MESHCONF_CAPAB_FORWARDING = 0x08,
682 IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING = 0x20, 689 IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING = 0x20,
690 IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL = 0x40,
683}; 691};
684 692
685/** 693/**
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index b4ecf267a34b..0ecf947ad378 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -258,6 +258,17 @@ config MAC80211_MESH_SYNC_DEBUG
258 258
259 Do not select this option. 259 Do not select this option.
260 260
261config MAC80211_MESH_PS_DEBUG
262 bool "Verbose mesh powersave debugging"
263 depends on MAC80211_DEBUG_MENU
264 depends on MAC80211_MESH
265 ---help---
266 Selecting this option causes mac80211 to print out very verbose mesh
267 powersave debugging messages (when mac80211 is taking part in a
268 mesh network).
269
270 Do not select this option.
271
261config MAC80211_TDLS_DEBUG 272config MAC80211_TDLS_DEBUG
262 bool "Verbose TDLS debugging" 273 bool "Verbose TDLS debugging"
263 depends on MAC80211_DEBUG_MENU 274 depends on MAC80211_DEBUG_MENU
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 4911202334d9..9d7d840aac6d 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -39,7 +39,8 @@ mac80211-$(CONFIG_MAC80211_MESH) += \
39 mesh_pathtbl.o \ 39 mesh_pathtbl.o \
40 mesh_plink.o \ 40 mesh_plink.o \
41 mesh_hwmp.o \ 41 mesh_hwmp.o \
42 mesh_sync.o 42 mesh_sync.o \
43 mesh_ps.o
43 44
44mac80211-$(CONFIG_PM) += pm.o 45mac80211-$(CONFIG_PM) += pm.o
45 46
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 661b878bd19c..f4f7e7691077 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -492,7 +492,10 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
492#ifdef CONFIG_MAC80211_MESH 492#ifdef CONFIG_MAC80211_MESH
493 sinfo->filled |= STATION_INFO_LLID | 493 sinfo->filled |= STATION_INFO_LLID |
494 STATION_INFO_PLID | 494 STATION_INFO_PLID |
495 STATION_INFO_PLINK_STATE; 495 STATION_INFO_PLINK_STATE |
496 STATION_INFO_LOCAL_PM |
497 STATION_INFO_PEER_PM |
498 STATION_INFO_NONPEER_PM;
496 499
497 sinfo->llid = le16_to_cpu(sta->llid); 500 sinfo->llid = le16_to_cpu(sta->llid);
498 sinfo->plid = le16_to_cpu(sta->plid); 501 sinfo->plid = le16_to_cpu(sta->plid);
@@ -501,6 +504,9 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
501 sinfo->filled |= STATION_INFO_T_OFFSET; 504 sinfo->filled |= STATION_INFO_T_OFFSET;
502 sinfo->t_offset = sta->t_offset; 505 sinfo->t_offset = sta->t_offset;
503 } 506 }
507 sinfo->local_pm = sta->local_pm;
508 sinfo->peer_pm = sta->peer_pm;
509 sinfo->nonpeer_pm = sta->nonpeer_pm;
504#endif 510#endif
505 } 511 }
506 512
@@ -1262,6 +1268,10 @@ static int sta_apply_parameters(struct ieee80211_local *local,
1262 changed = mesh_plink_inc_estab_count( 1268 changed = mesh_plink_inc_estab_count(
1263 sdata); 1269 sdata);
1264 sta->plink_state = params->plink_state; 1270 sta->plink_state = params->plink_state;
1271
1272 ieee80211_mps_sta_status_update(sta);
1273 ieee80211_mps_set_sta_local_pm(sta,
1274 sdata->u.mesh.mshcfg.power_mode);
1265 break; 1275 break;
1266 case NL80211_PLINK_LISTEN: 1276 case NL80211_PLINK_LISTEN:
1267 case NL80211_PLINK_BLOCKED: 1277 case NL80211_PLINK_BLOCKED:
@@ -1273,6 +1283,9 @@ static int sta_apply_parameters(struct ieee80211_local *local,
1273 changed = mesh_plink_dec_estab_count( 1283 changed = mesh_plink_dec_estab_count(
1274 sdata); 1284 sdata);
1275 sta->plink_state = params->plink_state; 1285 sta->plink_state = params->plink_state;
1286
1287 ieee80211_mps_sta_status_update(sta);
1288 ieee80211_mps_local_status_update(sdata);
1276 break; 1289 break;
1277 default: 1290 default:
1278 /* nothing */ 1291 /* nothing */
@@ -1289,6 +1302,9 @@ static int sta_apply_parameters(struct ieee80211_local *local,
1289 break; 1302 break;
1290 } 1303 }
1291 } 1304 }
1305
1306 if (params->local_pm)
1307 ieee80211_mps_set_sta_local_pm(sta, params->local_pm);
1292#endif 1308#endif
1293 } 1309 }
1294 1310
@@ -1777,6 +1793,15 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
1777 if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, mask)) 1793 if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, mask))
1778 conf->dot11MeshHWMPconfirmationInterval = 1794 conf->dot11MeshHWMPconfirmationInterval =
1779 nconf->dot11MeshHWMPconfirmationInterval; 1795 nconf->dot11MeshHWMPconfirmationInterval;
1796 if (_chg_mesh_attr(NL80211_MESHCONF_POWER_MODE, mask)) {
1797 conf->power_mode = nconf->power_mode;
1798 ieee80211_mps_local_status_update(sdata);
1799 }
1800 if (_chg_mesh_attr(NL80211_MESHCONF_AWAKE_WINDOW, mask)) {
1801 conf->dot11MeshAwakeWindowDuration =
1802 nconf->dot11MeshAwakeWindowDuration;
1803 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
1804 }
1780 return 0; 1805 return 0;
1781} 1806}
1782 1807
diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h
index 8f383a576016..4ccc5ed6237d 100644
--- a/net/mac80211/debug.h
+++ b/net/mac80211/debug.h
@@ -44,6 +44,12 @@
44#define MAC80211_MESH_SYNC_DEBUG 0 44#define MAC80211_MESH_SYNC_DEBUG 0
45#endif 45#endif
46 46
47#ifdef CONFIG_MAC80211_MESH_PS_DEBUG
48#define MAC80211_MESH_PS_DEBUG 1
49#else
50#define MAC80211_MESH_PS_DEBUG 0
51#endif
52
47#ifdef CONFIG_MAC80211_TDLS_DEBUG 53#ifdef CONFIG_MAC80211_TDLS_DEBUG
48#define MAC80211_TDLS_DEBUG 1 54#define MAC80211_TDLS_DEBUG 1
49#else 55#else
@@ -151,6 +157,10 @@ do { \
151 _sdata_dbg(MAC80211_MESH_SYNC_DEBUG, \ 157 _sdata_dbg(MAC80211_MESH_SYNC_DEBUG, \
152 sdata, fmt, ##__VA_ARGS__) 158 sdata, fmt, ##__VA_ARGS__)
153 159
160#define mps_dbg(sdata, fmt, ...) \
161 _sdata_dbg(MAC80211_MESH_PS_DEBUG, \
162 sdata, fmt, ##__VA_ARGS__)
163
154#define tdls_dbg(sdata, fmt, ...) \ 164#define tdls_dbg(sdata, fmt, ...) \
155 _sdata_dbg(MAC80211_TDLS_DEBUG, \ 165 _sdata_dbg(MAC80211_TDLS_DEBUG, \
156 sdata, fmt, ##__VA_ARGS__) 166 sdata, fmt, ##__VA_ARGS__)
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index cbde5cc49a40..059bbb82e84f 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -515,6 +515,9 @@ IEEE80211_IF_FILE(dot11MeshHWMProotInterval,
515 u.mesh.mshcfg.dot11MeshHWMProotInterval, DEC); 515 u.mesh.mshcfg.dot11MeshHWMProotInterval, DEC);
516IEEE80211_IF_FILE(dot11MeshHWMPconfirmationInterval, 516IEEE80211_IF_FILE(dot11MeshHWMPconfirmationInterval,
517 u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval, DEC); 517 u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval, DEC);
518IEEE80211_IF_FILE(power_mode, u.mesh.mshcfg.power_mode, DEC);
519IEEE80211_IF_FILE(dot11MeshAwakeWindowDuration,
520 u.mesh.mshcfg.dot11MeshAwakeWindowDuration, DEC);
518#endif 521#endif
519 522
520#define DEBUGFS_ADD_MODE(name, mode) \ 523#define DEBUGFS_ADD_MODE(name, mode) \
@@ -620,6 +623,8 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
620 MESHPARAMS_ADD(dot11MeshHWMPactivePathToRootTimeout); 623 MESHPARAMS_ADD(dot11MeshHWMPactivePathToRootTimeout);
621 MESHPARAMS_ADD(dot11MeshHWMProotInterval); 624 MESHPARAMS_ADD(dot11MeshHWMProotInterval);
622 MESHPARAMS_ADD(dot11MeshHWMPconfirmationInterval); 625 MESHPARAMS_ADD(dot11MeshHWMPconfirmationInterval);
626 MESHPARAMS_ADD(power_mode);
627 MESHPARAMS_ADD(dot11MeshAwakeWindowDuration);
623#undef MESHPARAMS_ADD 628#undef MESHPARAMS_ADD
624} 629}
625#endif 630#endif
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 6fb1168b9f16..c7591f73dbc3 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -65,7 +65,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
65 test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" 65 test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
66 66
67 int res = scnprintf(buf, sizeof(buf), 67 int res = scnprintf(buf, sizeof(buf),
68 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 68 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
69 TEST(AUTH), TEST(ASSOC), TEST(PS_STA), 69 TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
70 TEST(PS_DRIVER), TEST(AUTHORIZED), 70 TEST(PS_DRIVER), TEST(AUTHORIZED),
71 TEST(SHORT_PREAMBLE), 71 TEST(SHORT_PREAMBLE),
@@ -74,7 +74,8 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
74 TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), 74 TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
75 TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), 75 TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
76 TEST(INSERTED), TEST(RATE_CONTROL), 76 TEST(INSERTED), TEST(RATE_CONTROL),
77 TEST(TOFFSET_KNOWN)); 77 TEST(TOFFSET_KNOWN), TEST(MPSP_OWNER),
78 TEST(MPSP_RECIPIENT));
78#undef TEST 79#undef TEST
79 return simple_read_from_buffer(userbuf, count, ppos, buf, res); 80 return simple_read_from_buffer(userbuf, count, ppos, buf, res);
80} 81}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8faf360e0b4c..5fe9db707880 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -590,6 +590,11 @@ struct ieee80211_if_mesh {
590 s64 sync_offset_clockdrift_max; 590 s64 sync_offset_clockdrift_max;
591 spinlock_t sync_offset_lock; 591 spinlock_t sync_offset_lock;
592 bool adjusting_tbtt; 592 bool adjusting_tbtt;
593 /* mesh power save */
594 enum nl80211_mesh_power_mode nonpeer_pm;
595 int ps_peers_light_sleep;
596 int ps_peers_deep_sleep;
597 struct ps_data ps;
593}; 598};
594 599
595#ifdef CONFIG_MAC80211_MESH 600#ifdef CONFIG_MAC80211_MESH
@@ -1185,6 +1190,7 @@ struct ieee802_11_elems {
1185 struct ieee80211_meshconf_ie *mesh_config; 1190 struct ieee80211_meshconf_ie *mesh_config;
1186 u8 *mesh_id; 1191 u8 *mesh_id;
1187 u8 *peering; 1192 u8 *peering;
1193 __le16 *awake_window;
1188 u8 *preq; 1194 u8 *preq;
1189 u8 *prep; 1195 u8 *prep;
1190 u8 *perr; 1196 u8 *perr;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index f920da1201ab..35ac38871420 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -261,6 +261,9 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
261 *pos = IEEE80211_MESHCONF_CAPAB_FORWARDING; 261 *pos = IEEE80211_MESHCONF_CAPAB_FORWARDING;
262 *pos |= ifmsh->accepting_plinks ? 262 *pos |= ifmsh->accepting_plinks ?
263 IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; 263 IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
264 /* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */
265 *pos |= ifmsh->ps_peers_deep_sleep ?
266 IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL : 0x00;
264 *pos++ |= ifmsh->adjusting_tbtt ? 267 *pos++ |= ifmsh->adjusting_tbtt ?
265 IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00; 268 IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00;
266 *pos++ = 0x00; 269 *pos++ = 0x00;
@@ -286,6 +289,29 @@ mesh_add_meshid_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
286 return 0; 289 return 0;
287} 290}
288 291
292int mesh_add_awake_window_ie(struct sk_buff *skb,
293 struct ieee80211_sub_if_data *sdata)
294{
295 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
296 u8 *pos;
297
298 /* see IEEE802.11-2012 13.14.6 */
299 if (ifmsh->ps_peers_light_sleep == 0 &&
300 ifmsh->ps_peers_deep_sleep == 0 &&
301 ifmsh->nonpeer_pm == NL80211_MESH_POWER_ACTIVE)
302 return 0;
303
304 if (skb_tailroom(skb) < 4)
305 return -ENOMEM;
306
307 pos = skb_put(skb, 2 + 2);
308 *pos++ = WLAN_EID_MESH_AWAKE_WINDOW;
309 *pos++ = 2;
310 put_unaligned_le16(ifmsh->mshcfg.dot11MeshAwakeWindowDuration, pos);
311
312 return 0;
313}
314
289int 315int
290mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) 316mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
291{ 317{
@@ -629,6 +655,8 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
629 sdata->vif.bss_conf.basic_rates = 655 sdata->vif.bss_conf.basic_rates =
630 ieee80211_mandatory_rates(local, band); 656 ieee80211_mandatory_rates(local, band);
631 657
658 ieee80211_mps_local_status_update(sdata);
659
632 ieee80211_bss_info_change_notify(sdata, changed); 660 ieee80211_bss_info_change_notify(sdata, changed);
633 661
634 netif_carrier_on(sdata->dev); 662 netif_carrier_on(sdata->dev);
@@ -651,6 +679,10 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
651 sta_info_flush(sdata); 679 sta_info_flush(sdata);
652 mesh_path_flush_by_iface(sdata); 680 mesh_path_flush_by_iface(sdata);
653 681
682 /* free all potentially still buffered group-addressed frames */
683 local->total_ps_buffered -= skb_queue_len(&ifmsh->ps.bc_buf);
684 skb_queue_purge(&ifmsh->ps.bc_buf);
685
654 del_timer_sync(&sdata->u.mesh.housekeeping_timer); 686 del_timer_sync(&sdata->u.mesh.housekeeping_timer);
655 del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); 687 del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
656 del_timer_sync(&sdata->u.mesh.mesh_path_timer); 688 del_timer_sync(&sdata->u.mesh.mesh_path_timer);
@@ -828,6 +860,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
828 ieee80211_mesh_path_root_timer, 860 ieee80211_mesh_path_root_timer,
829 (unsigned long) sdata); 861 (unsigned long) sdata);
830 INIT_LIST_HEAD(&ifmsh->preq_queue.list); 862 INIT_LIST_HEAD(&ifmsh->preq_queue.list);
863 skb_queue_head_init(&ifmsh->ps.bc_buf);
831 spin_lock_init(&ifmsh->mesh_preq_queue_lock); 864 spin_lock_init(&ifmsh->mesh_preq_queue_lock);
832 spin_lock_init(&ifmsh->sync_offset_lock); 865 spin_lock_init(&ifmsh->sync_offset_lock);
833 866
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index aff301544c7f..eb336253b6b3 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -222,6 +222,8 @@ int mesh_add_meshid_ie(struct sk_buff *skb,
222 struct ieee80211_sub_if_data *sdata); 222 struct ieee80211_sub_if_data *sdata);
223int mesh_add_rsn_ie(struct sk_buff *skb, 223int mesh_add_rsn_ie(struct sk_buff *skb,
224 struct ieee80211_sub_if_data *sdata); 224 struct ieee80211_sub_if_data *sdata);
225int mesh_add_awake_window_ie(struct sk_buff *skb,
226 struct ieee80211_sub_if_data *sdata);
225int mesh_add_vendor_ies(struct sk_buff *skb, 227int mesh_add_vendor_ies(struct sk_buff *skb,
226 struct ieee80211_sub_if_data *sdata); 228 struct ieee80211_sub_if_data *sdata);
227int mesh_add_ds_params_ie(struct sk_buff *skb, 229int mesh_add_ds_params_ie(struct sk_buff *skb,
@@ -242,6 +244,21 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata);
242void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); 244void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh);
243const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method); 245const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method);
244 246
247/* mesh power save */
248void ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata);
249void ieee80211_mps_set_sta_local_pm(struct sta_info *sta,
250 enum nl80211_mesh_power_mode pm);
251void ieee80211_mps_set_frame_flags(struct ieee80211_sub_if_data *sdata,
252 struct sta_info *sta,
253 struct ieee80211_hdr *hdr);
254void ieee80211_mps_sta_status_update(struct sta_info *sta);
255void ieee80211_mps_rx_h_sta_process(struct sta_info *sta,
256 struct ieee80211_hdr *hdr);
257void ieee80211_mpsp_trigger_process(u8 *qc, struct sta_info *sta,
258 bool tx, bool acked);
259void ieee80211_mps_frame_release(struct sta_info *sta,
260 struct ieee802_11_elems *elems);
261
245/* Mesh paths */ 262/* Mesh paths */
246int mesh_nexthop_lookup(struct sk_buff *skb, 263int mesh_nexthop_lookup(struct sk_buff *skb,
247 struct ieee80211_sub_if_data *sdata); 264 struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 6b4603a90031..f0dd8742ed42 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -205,6 +205,7 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata,
205 struct sk_buff *skb) 205 struct sk_buff *skb)
206{ 206{
207 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 207 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
208 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
208 209
209 skb_set_mac_header(skb, 0); 210 skb_set_mac_header(skb, 0);
210 skb_set_network_header(skb, 0); 211 skb_set_network_header(skb, 0);
@@ -217,6 +218,7 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata,
217 info->control.vif = &sdata->vif; 218 info->control.vif = &sdata->vif;
218 info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; 219 info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
219 ieee80211_set_qos_hdr(sdata, skb); 220 ieee80211_set_qos_hdr(sdata, skb);
221 ieee80211_mps_set_frame_flags(sdata, NULL, hdr);
220} 222}
221 223
222/** 224/**
@@ -1080,6 +1082,10 @@ int mesh_nexthop_resolve(struct sk_buff *skb,
1080 u8 *target_addr = hdr->addr3; 1082 u8 *target_addr = hdr->addr3;
1081 int err = 0; 1083 int err = 0;
1082 1084
1085 /* Nulls are only sent to peers for PS and should be pre-addressed */
1086 if (ieee80211_is_qos_nullfunc(hdr->frame_control))
1087 return 0;
1088
1083 rcu_read_lock(); 1089 rcu_read_lock();
1084 err = mesh_nexthop_lookup(skb, sdata); 1090 err = mesh_nexthop_lookup(skb, sdata);
1085 if (!err) 1091 if (!err)
@@ -1151,6 +1157,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
1151 if (next_hop) { 1157 if (next_hop) {
1152 memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN); 1158 memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
1153 memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); 1159 memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
1160 ieee80211_mps_set_frame_flags(sdata, next_hop, hdr);
1154 err = 0; 1161 err = 0;
1155 } 1162 }
1156 1163
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index aa749818860e..d5786c3eaee2 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -212,6 +212,7 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
212 hdr = (struct ieee80211_hdr *) skb->data; 212 hdr = (struct ieee80211_hdr *) skb->data;
213 memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN); 213 memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
214 memcpy(hdr->addr2, mpath->sdata->vif.addr, ETH_ALEN); 214 memcpy(hdr->addr2, mpath->sdata->vif.addr, ETH_ALEN);
215 ieee80211_mps_set_frame_flags(sta->sdata, sta, hdr);
215 } 216 }
216 217
217 spin_unlock_irqrestore(&mpath->frame_queue.lock, flags); 218 spin_unlock_irqrestore(&mpath->frame_queue.lock, flags);
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 6787d696d94c..fe7c3334d6fe 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -201,6 +201,9 @@ static u32 __mesh_plink_deactivate(struct sta_info *sta)
201 sta->plink_state = NL80211_PLINK_BLOCKED; 201 sta->plink_state = NL80211_PLINK_BLOCKED;
202 mesh_path_flush_by_nexthop(sta); 202 mesh_path_flush_by_nexthop(sta);
203 203
204 ieee80211_mps_sta_status_update(sta);
205 ieee80211_mps_local_status_update(sdata);
206
204 return changed; 207 return changed;
205} 208}
206 209
@@ -503,6 +506,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
503 rssi_threshold_check(sta, sdata)) 506 rssi_threshold_check(sta, sdata))
504 mesh_plink_open(sta); 507 mesh_plink_open(sta);
505 508
509 ieee80211_mps_frame_release(sta, elems);
506out: 510out:
507 rcu_read_unlock(); 511 rcu_read_unlock();
508} 512}
@@ -633,6 +637,9 @@ int mesh_plink_open(struct sta_info *sta)
633 "Mesh plink: starting establishment with %pM\n", 637 "Mesh plink: starting establishment with %pM\n",
634 sta->sta.addr); 638 sta->sta.addr);
635 639
640 /* set the non-peer mode to active during peering */
641 ieee80211_mps_local_status_update(sdata);
642
636 return mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, 643 return mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
637 sta->sta.addr, llid, 0, 0); 644 sta->sta.addr, llid, 0, 0);
638} 645}
@@ -866,6 +873,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
866 sta->llid = llid; 873 sta->llid = llid;
867 mesh_plink_timer_set(sta, 874 mesh_plink_timer_set(sta,
868 mshcfg->dot11MeshRetryTimeout); 875 mshcfg->dot11MeshRetryTimeout);
876
877 /* set the non-peer mode to active during peering */
878 ieee80211_mps_local_status_update(sdata);
879
869 spin_unlock_bh(&sta->lock); 880 spin_unlock_bh(&sta->lock);
870 mesh_plink_frame_tx(sdata, 881 mesh_plink_frame_tx(sdata,
871 WLAN_SP_MESH_PEERING_OPEN, 882 WLAN_SP_MESH_PEERING_OPEN,
@@ -959,6 +970,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
959 changed |= mesh_set_short_slot_time(sdata); 970 changed |= mesh_set_short_slot_time(sdata);
960 mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", 971 mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
961 sta->sta.addr); 972 sta->sta.addr);
973 ieee80211_mps_sta_status_update(sta);
974 ieee80211_mps_set_sta_local_pm(sta,
975 mshcfg->power_mode);
962 break; 976 break;
963 default: 977 default:
964 spin_unlock_bh(&sta->lock); 978 spin_unlock_bh(&sta->lock);
@@ -998,6 +1012,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
998 mesh_plink_frame_tx(sdata, 1012 mesh_plink_frame_tx(sdata,
999 WLAN_SP_MESH_PEERING_CONFIRM, 1013 WLAN_SP_MESH_PEERING_CONFIRM,
1000 sta->sta.addr, llid, plid, 0); 1014 sta->sta.addr, llid, plid, 0);
1015 ieee80211_mps_sta_status_update(sta);
1016 ieee80211_mps_set_sta_local_pm(sta,
1017 mshcfg->power_mode);
1001 break; 1018 break;
1002 default: 1019 default:
1003 spin_unlock_bh(&sta->lock); 1020 spin_unlock_bh(&sta->lock);
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}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index a19089565c4b..c98be0593756 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1452,6 +1452,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
1452 } 1452 }
1453 } 1453 }
1454 1454
1455 /* mesh power save support */
1456 if (ieee80211_vif_is_mesh(&rx->sdata->vif))
1457 ieee80211_mps_rx_h_sta_process(sta, hdr);
1458
1455 /* 1459 /*
1456 * Drop (qos-)data::nullfunc frames silently, since they 1460 * Drop (qos-)data::nullfunc frames silently, since they
1457 * are used only to control station power saving mode. 1461 * are used only to control station power saving mode.
@@ -2090,7 +2094,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
2090 if (is_multicast_ether_addr(fwd_hdr->addr1)) { 2094 if (is_multicast_ether_addr(fwd_hdr->addr1)) {
2091 IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast); 2095 IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
2092 memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN); 2096 memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
2097 /* update power mode indication when forwarding */
2098 ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
2093 } else if (!mesh_nexthop_lookup(fwd_skb, sdata)) { 2099 } else if (!mesh_nexthop_lookup(fwd_skb, sdata)) {
2100 /* mesh power mode flags updated in mesh_nexthop_lookup */
2094 IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast); 2101 IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
2095 } else { 2102 } else {
2096 /* unable to resolve next hop */ 2103 /* unable to resolve next hop */
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 227233c3ff7f..47a0f0601768 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -120,6 +120,8 @@ static void cleanup_single_sta(struct sta_info *sta)
120 if (sta->sdata->vif.type == NL80211_IFTYPE_AP || 120 if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
121 sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 121 sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
122 ps = &sdata->bss->ps; 122 ps = &sdata->bss->ps;
123 else if (ieee80211_vif_is_mesh(&sdata->vif))
124 ps = &sdata->u.mesh.ps;
123 else 125 else
124 return; 126 return;
125 127
@@ -587,6 +589,12 @@ void sta_info_recalc_tim(struct sta_info *sta)
587 589
588 ps = &sta->sdata->bss->ps; 590 ps = &sta->sdata->bss->ps;
589 id = sta->sta.aid; 591 id = sta->sta.aid;
592#ifdef CONFIG_MAC80211_MESH
593 } else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) {
594 ps = &sta->sdata->u.mesh.ps;
595 /* TIM map only for PLID <= IEEE80211_MAX_AID */
596 id = le16_to_cpu(sta->plid) % IEEE80211_MAX_AID;
597#endif
590 } else { 598 } else {
591 return; 599 return;
592 } 600 }
@@ -745,8 +753,9 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
745 bool have_buffered = false; 753 bool have_buffered = false;
746 int ac; 754 int ac;
747 755
748 /* This is only necessary for stations on BSS interfaces */ 756 /* This is only necessary for stations on BSS/MBSS interfaces */
749 if (!sta->sdata->bss) 757 if (!sta->sdata->bss &&
758 !ieee80211_vif_is_mesh(&sta->sdata->vif))
750 return false; 759 return false;
751 760
752 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) 761 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
@@ -934,6 +943,11 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
934 if (time_after(jiffies, sta->last_rx + exp_time)) { 943 if (time_after(jiffies, sta->last_rx + exp_time)) {
935 sta_dbg(sta->sdata, "expiring inactive STA %pM\n", 944 sta_dbg(sta->sdata, "expiring inactive STA %pM\n",
936 sta->sta.addr); 945 sta->sta.addr);
946
947 if (ieee80211_vif_is_mesh(&sdata->vif) &&
948 test_sta_flag(sta, WLAN_STA_PS_STA))
949 atomic_dec(&sdata->u.mesh.ps.num_sta_ps);
950
937 WARN_ON(__sta_info_destroy(sta)); 951 WARN_ON(__sta_info_destroy(sta));
938 } 952 }
939 } 953 }
@@ -992,6 +1006,8 @@ static void clear_sta_ps_flags(void *_sta)
992 if (sdata->vif.type == NL80211_IFTYPE_AP || 1006 if (sdata->vif.type == NL80211_IFTYPE_AP ||
993 sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 1007 sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
994 ps = &sdata->bss->ps; 1008 ps = &sdata->bss->ps;
1009 else if (ieee80211_vif_is_mesh(&sdata->vif))
1010 ps = &sdata->u.mesh.ps;
995 else 1011 else
996 return; 1012 return;
997 1013
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index af7d78aa5523..5a1deba2c645 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -56,6 +56,8 @@
56 * @WLAN_STA_INSERTED: This station is inserted into the hash table. 56 * @WLAN_STA_INSERTED: This station is inserted into the hash table.
57 * @WLAN_STA_RATE_CONTROL: rate control was initialized for this station. 57 * @WLAN_STA_RATE_CONTROL: rate control was initialized for this station.
58 * @WLAN_STA_TOFFSET_KNOWN: toffset calculated for this station is valid. 58 * @WLAN_STA_TOFFSET_KNOWN: toffset calculated for this station is valid.
59 * @WLAN_STA_MPSP_OWNER: local STA is owner of a mesh Peer Service Period.
60 * @WLAN_STA_MPSP_RECIPIENT: local STA is recipient of a MPSP.
59 */ 61 */
60enum ieee80211_sta_info_flags { 62enum ieee80211_sta_info_flags {
61 WLAN_STA_AUTH, 63 WLAN_STA_AUTH,
@@ -78,6 +80,8 @@ enum ieee80211_sta_info_flags {
78 WLAN_STA_INSERTED, 80 WLAN_STA_INSERTED,
79 WLAN_STA_RATE_CONTROL, 81 WLAN_STA_RATE_CONTROL,
80 WLAN_STA_TOFFSET_KNOWN, 82 WLAN_STA_TOFFSET_KNOWN,
83 WLAN_STA_MPSP_OWNER,
84 WLAN_STA_MPSP_RECIPIENT,
81}; 85};
82 86
83#define ADDBA_RESP_INTERVAL HZ 87#define ADDBA_RESP_INTERVAL HZ
@@ -282,6 +286,9 @@ struct sta_ampdu_mlme {
282 * @t_offset_setpoint: reference timing offset of this sta to be used when 286 * @t_offset_setpoint: reference timing offset of this sta to be used when
283 * calculating clockdrift 287 * calculating clockdrift
284 * @ch_width: peer's channel width 288 * @ch_width: peer's channel width
289 * @local_pm: local link-specific power save mode
290 * @peer_pm: peer-specific power save mode towards local STA
291 * @nonpeer_pm: STA power save mode towards non-peer neighbors
285 * @debugfs: debug filesystem info 292 * @debugfs: debug filesystem info
286 * @dead: set to true when sta is unlinked 293 * @dead: set to true when sta is unlinked
287 * @uploaded: set to true when sta is uploaded to the driver 294 * @uploaded: set to true when sta is uploaded to the driver
@@ -379,6 +386,10 @@ struct sta_info {
379 s64 t_offset; 386 s64 t_offset;
380 s64 t_offset_setpoint; 387 s64 t_offset_setpoint;
381 enum nl80211_chan_width ch_width; 388 enum nl80211_chan_width ch_width;
389 /* mesh power save */
390 enum nl80211_mesh_power_mode local_pm;
391 enum nl80211_mesh_power_mode peer_pm;
392 enum nl80211_mesh_power_mode nonpeer_pm;
382#endif 393#endif
383 394
384#ifdef CONFIG_MAC80211_DEBUGFS 395#ifdef CONFIG_MAC80211_DEBUGFS
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index d041de056b7f..43439203f4e4 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -472,6 +472,13 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
472 return; 472 return;
473 } 473 }
474 474
475 /* mesh Peer Service Period support */
476 if (ieee80211_vif_is_mesh(&sta->sdata->vif) &&
477 ieee80211_is_data_qos(fc))
478 ieee80211_mpsp_trigger_process(
479 ieee80211_get_qos_ctl(hdr),
480 sta, true, acked);
481
475 if ((local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) && 482 if ((local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) &&
476 (rates_idx != -1)) 483 (rates_idx != -1))
477 sta->last_tx_rate = info->status.rates[rates_idx]; 484 sta->last_tx_rate = info->status.rates[rates_idx];
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 7892b0a8873e..2ef0e19b06bb 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -329,6 +329,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
329 329
330 if (sdata->vif.type == NL80211_IFTYPE_AP) 330 if (sdata->vif.type == NL80211_IFTYPE_AP)
331 ps = &sdata->u.ap.ps; 331 ps = &sdata->u.ap.ps;
332 else if (ieee80211_vif_is_mesh(&sdata->vif))
333 ps = &sdata->u.mesh.ps;
332 else 334 else
333 continue; 335 continue;
334 336
@@ -372,18 +374,20 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
372 /* 374 /*
373 * broadcast/multicast frame 375 * broadcast/multicast frame
374 * 376 *
375 * If any of the associated stations is in power save mode, 377 * If any of the associated/peer stations is in power save mode,
376 * the frame is buffered to be sent after DTIM beacon frame. 378 * the frame is buffered to be sent after DTIM beacon frame.
377 * This is done either by the hardware or us. 379 * This is done either by the hardware or us.
378 */ 380 */
379 381
380 /* powersaving STAs currently only in AP/VLAN mode */ 382 /* powersaving STAs currently only in AP/VLAN/mesh mode */
381 if (tx->sdata->vif.type == NL80211_IFTYPE_AP || 383 if (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
382 tx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { 384 tx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
383 if (!tx->sdata->bss) 385 if (!tx->sdata->bss)
384 return TX_CONTINUE; 386 return TX_CONTINUE;
385 387
386 ps = &tx->sdata->bss->ps; 388 ps = &tx->sdata->bss->ps;
389 } else if (ieee80211_vif_is_mesh(&tx->sdata->vif)) {
390 ps = &tx->sdata->u.mesh.ps;
387 } else { 391 } else {
388 return TX_CONTINUE; 392 return TX_CONTINUE;
389 } 393 }
@@ -1473,12 +1477,14 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
1473 hdr = (struct ieee80211_hdr *) skb->data; 1477 hdr = (struct ieee80211_hdr *) skb->data;
1474 info->control.vif = &sdata->vif; 1478 info->control.vif = &sdata->vif;
1475 1479
1476 if (ieee80211_vif_is_mesh(&sdata->vif) && 1480 if (ieee80211_vif_is_mesh(&sdata->vif)) {
1477 ieee80211_is_data(hdr->frame_control) && 1481 if (ieee80211_is_data(hdr->frame_control) &&
1478 !is_multicast_ether_addr(hdr->addr1) && 1482 is_unicast_ether_addr(hdr->addr1)) {
1479 mesh_nexthop_resolve(skb, sdata)) { 1483 if (mesh_nexthop_resolve(skb, sdata))
1480 /* skb queued: don't free */ 1484 return; /* skb queued: don't free */
1481 return; 1485 } else {
1486 ieee80211_mps_set_frame_flags(sdata, NULL, hdr);
1487 }
1482 } 1488 }
1483 1489
1484 ieee80211_set_qos_hdr(sdata, skb); 1490 ieee80211_set_qos_hdr(sdata, skb);
@@ -2445,12 +2451,14 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2445 2 + /* NULL SSID */ 2451 2 + /* NULL SSID */
2446 2 + 8 + /* supported rates */ 2452 2 + 8 + /* supported rates */
2447 2 + 3 + /* DS params */ 2453 2 + 3 + /* DS params */
2454 256 + /* TIM IE */
2448 2 + (IEEE80211_MAX_SUPP_RATES - 8) + 2455 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
2449 2 + sizeof(struct ieee80211_ht_cap) + 2456 2 + sizeof(struct ieee80211_ht_cap) +
2450 2 + sizeof(struct ieee80211_ht_operation) + 2457 2 + sizeof(struct ieee80211_ht_operation) +
2451 2 + sdata->u.mesh.mesh_id_len + 2458 2 + sdata->u.mesh.mesh_id_len +
2452 2 + sizeof(struct ieee80211_meshconf_ie) + 2459 2 + sizeof(struct ieee80211_meshconf_ie) +
2453 sdata->u.mesh.ie_len); 2460 sdata->u.mesh.ie_len +
2461 2 + sizeof(__le16)); /* awake window */
2454 if (!skb) 2462 if (!skb)
2455 goto out; 2463 goto out;
2456 2464
@@ -2462,6 +2470,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2462 eth_broadcast_addr(mgmt->da); 2470 eth_broadcast_addr(mgmt->da);
2463 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); 2471 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
2464 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); 2472 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
2473 ieee80211_mps_set_frame_flags(sdata, NULL, (void *) mgmt);
2465 mgmt->u.beacon.beacon_int = 2474 mgmt->u.beacon.beacon_int =
2466 cpu_to_le16(sdata->vif.bss_conf.beacon_int); 2475 cpu_to_le16(sdata->vif.bss_conf.beacon_int);
2467 mgmt->u.beacon.capab_info |= cpu_to_le16( 2476 mgmt->u.beacon.capab_info |= cpu_to_le16(
@@ -2475,12 +2484,14 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2475 2484
2476 if (ieee80211_add_srates_ie(sdata, skb, true, band) || 2485 if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
2477 mesh_add_ds_params_ie(skb, sdata) || 2486 mesh_add_ds_params_ie(skb, sdata) ||
2487 ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb) ||
2478 ieee80211_add_ext_srates_ie(sdata, skb, true, band) || 2488 ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
2479 mesh_add_rsn_ie(skb, sdata) || 2489 mesh_add_rsn_ie(skb, sdata) ||
2480 mesh_add_ht_cap_ie(skb, sdata) || 2490 mesh_add_ht_cap_ie(skb, sdata) ||
2481 mesh_add_ht_oper_ie(skb, sdata) || 2491 mesh_add_ht_oper_ie(skb, sdata) ||
2482 mesh_add_meshid_ie(skb, sdata) || 2492 mesh_add_meshid_ie(skb, sdata) ||
2483 mesh_add_meshconf_ie(skb, sdata) || 2493 mesh_add_meshconf_ie(skb, sdata) ||
2494 mesh_add_awake_window_ie(skb, sdata) ||
2484 mesh_add_vendor_ies(skb, sdata)) { 2495 mesh_add_vendor_ies(skb, sdata)) {
2485 pr_err("o11s: couldn't add ies!\n"); 2496 pr_err("o11s: couldn't add ies!\n");
2486 goto out; 2497 goto out;
@@ -2734,6 +2745,8 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
2734 goto out; 2745 goto out;
2735 2746
2736 ps = &sdata->u.ap.ps; 2747 ps = &sdata->u.ap.ps;
2748 } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
2749 ps = &sdata->u.mesh.ps;
2737 } else { 2750 } else {
2738 goto out; 2751 goto out;
2739 } 2752 }
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 139ad9b66c39..6cb71a350edd 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -805,6 +805,10 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
805 elems->peering = pos; 805 elems->peering = pos;
806 elems->peering_len = elen; 806 elems->peering_len = elen;
807 break; 807 break;
808 case WLAN_EID_MESH_AWAKE_WINDOW:
809 if (elen >= 2)
810 elems->awake_window = (void *)pos;
811 break;
808 case WLAN_EID_PREQ: 812 case WLAN_EID_PREQ:
809 elems->preq = pos; 813 elems->preq = pos;
810 elems->preq_len = elen; 814 elems->preq_len = elen;
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 906f00cd6d2f..afba19cb6f87 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -191,6 +191,15 @@ void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
191 191
192 /* qos header is 2 bytes */ 192 /* qos header is 2 bytes */
193 *p++ = ack_policy | tid; 193 *p++ = ack_policy | tid;
194 *p = ieee80211_vif_is_mesh(&sdata->vif) ? 194 if (ieee80211_vif_is_mesh(&sdata->vif)) {
195 (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8) : 0; 195 /* preserve RSPI and Mesh PS Level bit */
196 *p &= ((IEEE80211_QOS_CTL_RSPI |
197 IEEE80211_QOS_CTL_MESH_PS_LEVEL) >> 8);
198
199 /* Nulls don't have a mesh header (frame body) */
200 if (!ieee80211_is_qos_nullfunc(hdr->frame_control))
201 *p |= (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8);
202 } else {
203 *p = 0;
204 }
196} 205}