aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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}